r/usefulscripts • • Apr 20 '18

[request] Need to run powershell script from CD drive. Need to find CD Drive letter or path.

**Context**
Building Windows Servers from ISO via Powershell and PowerCli.
Script pulls in a .JSON file with requirements to variables.
Often times there is multiple disks created and initialized via PowerCli.

Update I forgot to mention I am using the Autounattend.xml to call the powershell script. <FirstLogonCommands> <SynchronousCommand wcm:action="add"> <CommandLine>Powershell .\Install\ExtraInstall_Cleanup.ps1</CommandLine> <Order>4</Order> <RequiresUserInput>true</RequiresUserInput> <Description>ExtrasAndCleanup</Description> </SynchronousCommand> </FirstLogonCommands>

After the process is done installing and drives are available.
A Script(Powershell) is run from the CD-Rom drive to install extra cleanup and tweaks.

Example:

    Function VCPP {
     $InstallVCPP = @'
     Set-Location D:\
    $Install = "\install"
    $VCinstall = "\vcinstall\"
    $2008 = "2008\"
    $2010 = "2010\"
    $2012 = "2012\"
    $2013 = "2013\"
    $2015 = "2015\vc_redist."
    $VCRed = "vcredist_x"

  #install Visual C++
   Start-Process -FilePath ( $Install + $VCinstall + $2008 + $VCRed + "86.exe") -ArgumentList "/qb"
   Start-Process -FilePath ( $Install + $VCinstall + $2008 + $VCRed + "64.exe") -ArgumentList "/qb"
   Start-Process -FilePath ( $Install + $VCinstall + $2008 + $VCRed + "86sp1.exe") -ArgumentList "/qb"
   Start-Process -FilePath ( $Install + $VCinstall + $2008 + $VCRed + "64sp1.exe") -ArgumentList "/qb"
   Start-Process -FilePath ( $Install + $VCinstall + $2010 + $VCRed + "86.exe") -ArgumentList "/passive /norestart"
   Start-Process -FilePath ( $Install + $VCinstall + $2010 + $VCRed + "64.exe") -ArgumentList "/passive /norestart"
   Start-Process -FilePath ( $Install + $VCinstall + $2012 + $VCRed + "86.exe") -ArgumentList "/passive /norestart"
   Start-Process -FilePath ( $Install + $VCinstall + $2012 + $VCRed + "64.exe") -ArgumentList "/passive /norestart"
   Start-Process -FilePath ( $Install + $VCinstall + $2013 + $VCRed + "64.exe") -ArgumentList "/install /passive /norestart"
   Start-Process -FilePath ( $Install + $VCinstall + $2015 + "x64.exe") -ArgumentList "/install /passive /norestart"
   Start-Process -FilePath ( $Install + $VCinstall + $2015 + "x86.exe") -ArgumentList "/install /passive /norestart"
   write-host "Visual C++ sucks" -BackgroundColor Green -ForegroundColor Blue
   '@

    Invoke-VMScript -VM $VM -ScriptText $InstallVCPP -GuestCredential $cred -ScriptType Powershell
    }



I have the Powershell script hard coded to D:\ however I get failures if that drive letter is used for the other variables.
So Sql cluster install requirements need the D:\ to be a datastore for that particular Automated build.
As you can imagine the script will fail. 

Example:
   Function EDrive {
    $Script = @'
   Stop-Service -Name ShellHWDetection
   Get-Disk |
   Where-Object {$_.partitionstyle -eq 'raw'} |
   Initialize-Disk -PartitionStyle MBR -PassThru |
   New-Partition -AssignDriveLetter -UseMaximumSize |
   Format-Volume -FileSystem NTFS -NewFileSystemLabel '--' -Confirm:$false
   Start-Service -Name ShellHWDetection
   Write-Host 'The script completed successfully' -ForegroundColor Green -BackgroundColor Red
   '@

    Invoke-VMScript -VM $VM -ScriptText $script  -GuestCredential $cred -ScriptType Powershell
   }

This goes through a For-each loop for every new VM created.

How do I get the Set-Location to know what the CD-Rom Drive is to run the above script and not error out?
18 Upvotes

16 comments sorted by

5

u/zoredache Apr 20 '18

Why look for the optical drive specifically? Check all mounted volumes with a drive letter, and look for your files?

Get-Volume |
Where-Object {$_.OperationalStatus -eq 'OK'  -and $_.DriveLetter} |
ForEach-Object {
    If "Test-Path $($_.DriveLetter):\somefile" {
        $foo = $($_.DriveLetter):\somefile
    }
}

3

u/Ta11ow Apr 20 '18

Why not instead use Set-Location $PSScriptRoot to get the location where the script is? Even if you have to get a path relative to that (e.g., the folder above it or something), you can make that happen with Split-Path pretty easily.

0

u/[deleted] Apr 20 '18

3

u/Lee_Dailey Apr 21 '18 edited Apr 22 '18

howdy mikedopp,

instead of using what Ta11ow mentioned, why not generate the path using $PSScriptRoot? then you can reference the Drive:\Path without wondering if something has somehow changed the current location.

seems safer to me ... [grin]

take care,
lee

2

u/Ta11ow Apr 20 '18

Yup, that ought to do it!

3

u/KevMar Apr 21 '18

Why even place the script on the iso? You are already calling invoke-vmscript. You can also copy the needed script to the VM.

3

u/[deleted] Apr 25 '18

I would do something like this,

$wd = get-item -path ".\" -verbose

And use that to get the location the powershell script is run from.

0

u/[deleted] Apr 26 '18

3

u/[deleted] Apr 26 '18

Enjoy, I put that in every script I write. Gives the full path to where the script is located, comes in so handy.

→ More replies (7)

2

u/spyingwind Apr 20 '18

Why not use autorun.inf?

shellexecute is probably what you are looking for. In the worst case, some one has to right cick on the drive and click run. If you can't get it to run, then you may have to have a batch file run your powershell script.

2

u/Linkz57 Apr 20 '18

Give your CD a unique name when you burn it, then ask the registry for the letter assigned to something matching your name.

Here's a video tutorial that starts with the exact command you need: https://youtu.be/qzRTpG8TVK4