Rectangle 27 3

I can only think of two ways go to about modifying IIS's configuration programmatically, from classic ASP. The first is to use COM classes such as ADSI or WMI to manipulate the configuration. The second would leverage the new ASP.Net classes that Microsoft introduced, Microsoft.Web.Administration. (For completeness, you could also use System.DirectoryServices, but these classes are just a managed wrapper around ADSI.)

I'm going to discuss the COM-based solution first, since this approach would involve the least amount of overhead. I'm going to focus on ADSI, as opposed to WMI, since that's what I've used in the past. ADSI can be used add sites, vdirs, apps, etc.

Dim myNewSiteID, oIIsWebServiceObj, oBindings 

oBindings = Array(0) 
Set oBindings(0) = providerObj.get("ServerBinding").SpawnInstance_() 
oBindings(0).IP = "192.168.1.1" 
oBindings(0).Port = "80" 
oBindings(0).Hostname = "yournewsite.example.com"

Set oIIsWebServiceObj = GetObject("IIS://MachineName/W3SVC")
myNewSiteID = oIIsWebServiceObj.CreateNewSite("NewSite", oBindings, _
       "C:\Sites\yournewsite")

To create a new virtual directory, you could use:

Dim IIsWebVDirRootObj, IIsWebVDirObj
Set IIsWebVDirRootObj = GetObject("IIS://localhost/W3SVC/1/Root") 
Set IIsWebVDirObj = IIsWebVDirRootObj.Create("IIsWebVirtualDir", "NewVDir") 
IIsWebVDirObj.Put "Path", "C:\NewContent"  
IIsWebVDirObj.Put "AccessRead", True 
IIsWebVDirObj.Put "AccessScript", True 
IIsWebVDirObj.SetInfo

I'm 95% certain that in order to use either ADSI or WMI, you're going to need to enable the IIS6 Compatibility, since these COM objects attempt to manipulate the metabase, which newer versions of IIS no longer use. To enable IIS6 compatibility, see this MSDN page for IIS 7.5 or this MSDN page for IIS8.

If I was dead-set on using .Net somehow, I'd choose Microsoft.Web.Administration over System.DirectoryServices. No matter which .Net class you go with, you're going to have to wrap it to be able to use it from classic asp, since there's no native way to call .Net. In order to do this, you've need to wrap any code that you write in a CCW - a COM-Callable Wrapper. It's entirely possible to do this in such a way that you write all of your code in .Net, and instantiate a COM component that is just a container for all of the .Net code. I won't go into detail as to how to wrap .net code in a CCW, but your CCW'd .Net code would be as simple as:

ServerManager serverManager = new ServerManager();
Site mySite = serverManager.Sites.Add("NewSite", "C:\\Sites\\yournewsite", 80);
mySite.ServerAutoStart = true;
serverManager.CommitChanges();

Now, the bigger problem: You are running as IUSR, or IUSR_MachineName, or some limited account that has absolutely no permissions to muck with IIS's configuration. One way or another, you're going to have to gain more permission. You might be able to use impersonation in classic asp, but the other approach is to change the identity that your application is running as. In your case, as absolutely scary as it is, you'd need to run as something much more privileged than IUSR.

Or, just turn off Anonymous Authentication, and enable Basic Auth. Then, grant sufficient privileges to the user that will be authenicating to the server, and the code should run fine.

Thank you! Approach 1 looks fantastic. I will try to set it up this evening. Permissions are obviously a concern. If I open up this hole for this one piece of code, it opens it for everything on this site. I might have to create a second app, like a web service or something to handle this. If that is the case, I could do it as .net.

Create a virtual directory in IIS from Classic ASP - Stack Overflow

iis asp-classic virtual-directory
Rectangle 27 15

What about your codepage definition at the top of your page?

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>

Thanks a lot ! It works for me. I just add that script at my page. Thanks a lot! I can't reply immediately 'coz I can't be online that days. Thanks.

Classic ASP: How to write unicode string data in classic ASP? - Stack ...

unicode asp-classic utf-8
Rectangle 27 15

The Content-Type meta header informs the browser to treat the content sent as a UTF-8 encoded text stream. It doesn't ensure that the stream sent is actually UTF-8. To handle UTF-8 correctly you need to do 3 things:-

  • Ensure your static content is saved in a UTF-8 compatible encoding.
  • Inform the client that the content is UTF-8 encoded.

Item 1 requires either that you actually save the ASP file as a UTF-8 encoded file or that all your static content in the file is within the ASCII character range (0-127). Note if you save as UTF-8 then all your server-side script must use characters within the ASCII character range. In Visual Studio you can do so by "Saving the file AS..." and then clicking on the little arrow on the Save button.

Item 2 requires that the Response.CodePage property is set to the UTF-8 code page 65001, you can do this in code or by adding the attribute CODEPAGE=65001 to the <%@ %> declarations on the first line of the ASP file. If you do it in code you must set it before any calls to Response.Write. AND: do not use chr or asc functions (these are buggy when using 65001) but use chrw and ascw instead.

Item 3 requires that the Content-Type header contains the charset=UTF-8 qualifier. As you are already doing you can do this with the META header. Personally I find that to be a bit of kludge, I prefer to use Response.Charset = "UTF-8" in code. This places the qualifier on the true Content-Type HTTP header.

On our site even though we had the meta element added in the html I still had to add the Response.Charset, thanks Anythony.

Classic ASP: How to write unicode string data in classic ASP? - Stack ...

unicode asp-classic utf-8
Rectangle 27 8

We're moving back to not trying to abstract away fundamental concepts like HTML and HTTP Requests. On the UI end, that translates into the Views being more tightly integrated with the output, which isn't a bad thing. the classic ASP model translated into having everything tightly integrated with the output, which is a bad thing.

asp.net mvc - Are we moving towards classic ASP using MVC framework in...

asp.net-mvc asp-classic .net-3.5 tags
Rectangle 27 1

No, there's not a default built in implementation for encrypting/decrypting a string in classic ASP. That's why there are a million custom examples on how to encrypt/decrypt strings in classic ASP. It's really not as "involved" as you would think. For example, check out this example from 2002:

Scrambling/Unscrambling a string in Classic ASP - Stack Overflow

asp-classic
Rectangle 27 21

Fix #2 - Copy all byte arrays into a string of byte values and work against that, or provide a substitute for instrb that does its own iteration over the array.

Function InstrBNew(startPos, inputArray, searchChar)

  if LenB(searchChar) = 1 Then
    Dim loc
    For loc = startPos to Lenb(inputArray)
      if MidB(inputArray, loc, 1) = searchChar then Exit For
    Next
    InstrBNew = loc
  Else
    InstrBNew = InstrB(startPos, inputArray, searchChar)
  End If
End Function

Fix #3 - Microsoft has released a hotfix. This will go out to everyone in January 2016. You can get it early here. https://support.microsoft.com/en-us/kb/3125446

The problem seems to be that the InstrB function in vbScript now returns a value of 1 under the following conditions.

  • When you are searching a byte array (Such as Response.BinaryRead). This isn't very common in ASP or VBScript, but file uploads is one of those times when you're doing it.
  • When you are searching for a single byte

If you are searching a string, or if you are searching for a multibyte pattern, then InstrB works properly.

PosEnd = InstrB(PosBeg, ByteArray, chrb(13))

On my broken systems, this function always returns a 1, even though there is no byte value 13 at position 1. It returns 1 for any value when searching a byte array. The classic ASP file upload components, which is why we're all on this thread, run into this situation because they're parsing that byte array looking for delimiters.

PosEnd = InstrB(PosBeg,ByteArray,getByteString("FormBoundary"))
PosEnd = InstrB(PosBeg,ByteArray,getByteString(vbCRLF))
PosEnd = InstrB(PosBeg,"Normal string", chrb(103)) ' Search for letter g in a string

These above lines work fine and as expected. Multibyte searches and matches against a string work expectedly.

This problem hit me simultaneously across multiple servers last night. I saw that windows system updates ran last night also. Narrowing it down, I found that MS15-124 (KB3104002 Cumulative security update for IE11) contained an update for vbscript.dll. I removed this update and now the code returns to working properly.

I filed an issue on their "IE Connect" system, since it was included in an IE update, but I'm not sure if that's the right place.

I've attached a test case. On broken systems, it will return "5, 1, 5". On working systems it will return "5, 5, 5"

Hoping for a fix. Some of this old code is running on systems I don't have access to.

' Test.vbs
Dim byteArray, byteArray2, byteArray3, bPosition
Dim responseText

' byte string
' "hello hello"
byteArray = chrb(104) & chrb(101) & chrb(108) & chrb(108) & chrb(111) & chrb(32) & chrb(104) & chrb(101) & chrb(108) & chrb(108) & chrb(111) & chrb(0)

' byte array - What Response.BinaryRead is
byteArray2 = TextToBytes(byteArray)

' Vartype: http://stackoverflow.com/questions/3281355/get-the-type-of-a-variable-in-vbscript
ResponseText = ResponseText + "blen: " & lenb(byteArray) & vbCRLF
ResponseText = ResponseText + "type: " & vartype(byteArray) & vbCRLF

ResponseText = ResponseText + "blen: " & lenb(byteArray2) & vbCRLF
ResponseText = ResponseText + "type: " & vartype(byteArray2) & vbCRLF

bPosition = instrb(1, byteArray, chrb(111))
ResponseText = ResponseText + "Position in string: " & bPosition & vbCRLF

bPosition = instrb(1, byteArray2, chrb(111))
ResponseText = ResponseText + "Position in byte array: " & bPosition & vbCRLF

bPosition = instrb(1, byteArray2, chrb(111) & chrb(32))
ResponseText = ResponseText + "Position in byte array: " & bPosition & vbCRLF

WScript.Echo ResponseText

' Converts a string (8) to a vbArray of bytes (8192 + 17)
' I'm not sure how else to create a vbArray of bytes. It does not seem to be a common data type in vbscript
Private Function TextToBytes(ByRef pbinBinaryData)
    Dim lobjRs
    Dim llngLength
    Dim lbinBuffer
    CONST adLongVarBinary = 205
    llngLength = LenB(pbinBinaryData)
    Set lobjRs = CreateObject("ADODB.Recordset")
    Call lobjRs.Fields.Append("BinaryData", adLongVarBinary, llngLength)
    Call lobjRs.Open()
    Call lobjRs.AddNew()
    Call lobjRs.Fields("BinaryData").AppendChunk(pbinBinaryData)
    Call lobjRs.Update()
    lbinBuffer = lobjRs.Fields("BinaryData").GetChunk(llngLength)
    Call lobjRs.Close()
    Set lobjRs = Nothing
    TextToBytes = lbinBuffer
End Function

I would recommend Fix #3 and to apply the hotfix rather than removing the update.

vbscript - Uploading a file in classic asp - Stack Overflow

file-upload vbscript asp-classic
Rectangle 27 2

This blog post provides an example of using a hashing function implemented in .NET in Classic ASP code.

Basically, using BCrypt.Net, you should be able to create a 'COM-visible' wrapper interface for the relevant BCrypt.Net class methods and then be able to write Classic ASP code like the following:

Dim objBCrypt
Set objBCrypt = CreateObject("BCryptComInterface")

Dim strHash
Set strHash = objBCrypt.HashPassword(the_password_to_be_hashed)

Note that the BCrypt class BCrypt.Net.BCrypt has three overloaded methods with the name HashPassword; I'm assuming that the method HashPassword in the COM interface corresponds to the .NET method that only accepts a single parameter. [The other methods would be accessed as HashPassword_2 and HashPassword_3. See this answer to the SO question .net - Overloads in COM interop (CCW) - IDispatch names include suffix (_2, _3, etc) for more details.]

I'm pretty sure BCrypt has no COM visible types so you'd have to write a COM wrapper to use it in ASP.

security - Is there any way to Hash a password using BCrypt in classic...

security hash asp-classic passwords bcrypt
Rectangle 27 20

To focus on the specific question ("benefits of Classic vs .Net"), there are only two things I can think of Classic does that .Net won't:

1) Includes. They just don't work like you expect in ASP.Net. Of course, ASP.Net provides much better ways of accomplishing the same thing, but it's still a bit of a loss and can make migrating an old site to .Net a pain.

2) ASP.Net won't go above the root folder for the application. Where I'm at we have a rather complex intranet that's still mostly classic ASP, with a smattering of .Net apps here and there as things are updated or new stuff added. It would be nice to be able to keep one copy of common code up fairly high in the folder hierarchy but still have each individual app isolated to it's own VD. But then, that's what source control is for, so it's not a big deal.

For me, the biggest advantage moving from Classic ASP and ASP.Net so far is the IDE. It's so nice to be able to right click on a function call and choose "Go to Definition" rather than having to dig around to find the file where the function is actually implemented. Huge time-saver. And intellisense support and type safety when calling functions is a boon as well.

Voted up for actually answering the question in the title ;)

Second's wrong. You can access outside the folder =)

Are there benefits to Classic ASP over ASP.net - Stack Overflow

asp.net asp-classic
Rectangle 27 1

How do I do a forward instead of redirect in classic ASP?

I guess you mean pass the existing form data to different page? For this use Server.Transfer method.

How do I set a request attribute in classic ASP without using a form?

You can't it's Read Only. If you mean how it's possible to imitate Posting form data without actual form, it's possible using basic AJAX and you must assume every visitor can do it, meaning you can't trust Request.Form values. They can easily be spoofed.

Differences of Servlet and Classic ASP in handling Requests - Stack Ov...

asp-classic
Rectangle 27 12

Use Request.ServerVariables("HTTP_HOST") to get the host part so that you can check if it starts with www. or not.

If it doesn't then just issue a Response.Redirect() to the appropriate URL since it'll do a 302 for you:

If Left(Request.ServerVariables("HTTP_HOST"), 4) <> "www." Then
  Dim newUri
  'Build the redirect URI by prepending http://www. to the actual HTTP_HOST
  'and adding in the URL (i.e. the page the user requested)
  newUri = "http://www." & Request.ServerVariables("HTTP_HOST") & Request.ServerVariables("URL")

  'If there were any Querystring arguments pass them through as well
  If Request.ServerVariables("QUERY_STRING") <> "" Then
    newUri = newUri & "?" & Request.ServerVariables("QUERY_STRING")
  End If

  'Finally make the redirect
  Response.Redirect(newUri)
End If

The above does a redirect ensuring the requested page and querystring are preserved

Using this code from RobV with the 302 redirect which I posted in my answer would be the complete solution.

Response.Redirect()

Thanks for the solution

redirect - Url Redirection in Classic Asp page - Stack Overflow

asp-classic redirect http-status-code-302
Rectangle 27 3

The placement of the <script> tag on the bottom of the pages has two key reasons:

  • The HTML content is loaded before the JavaScript, meaning that the user sees your content earlier on
  • Inside the script, you can assume, that all the HTML is already loaded and is available to the DOM (so no need to wait for it)

Placement of server-side <script runat="server"> blocks have no impact as they are never rendered at the client. Using <script runat="server"> is the equivalent to <% %>.

@Lankymart Honestly, I've never written any ASP / ASP.Net code, but does it really matter where this kind of script is executed inside the ASP-file in terms of performance?

@G_hi3: As Lankymart points out, positioning of the script tags is irrelevant, as the page is actually being built by the server. The position of the script tag within the page is basically where that particular part will be executing at. For instance, you may have a server side script tag (which is usually shortened to <%, your code in the middle and closed using %>) which renders a list box or even table for you at that point.

I was agreeing with you. The only real thing to bear in mind is breaking in and out of server-side code can have a performance impact.

performance - JavaScript in classic ASP: Do the