I am using the following code to build some projects using PowerShell but this is taking nearly 30 minutes of time and some times it is taking more than that too, here is the PowerShell script I had when I execute it locally it is getting build in
$sourceDirectory = "D:\Service"
$SolutionToBuild = #("Solution1.sln","Solution2.sln","Solution3.sln","Solution4.sln")
$projectFiles = Get-ChildItem -Path "$sourceDirectory" -Filter *.sln -Recurse
foreach($solution in $SolutionToBuild)
{
foreach($projectFile in $projectFiles)
{
if($projectFile.Name -eq $solution)
{
write-host $projectFile.Name;
$SlnFilePath = $projectFile.FullName
$BuildParameters = """$SlnFilePath"" /Build Release|x86"
$CleanParameters = """$SlnFilePath"" /Clean Release|x86"
Start-Process -FilePath $vsPath -ArgumentList $CleanParameters -Wait
Start-Process -FilePath $vsPath -ArgumentList $BuildParameters -Wait
break;
}
}
}
So can one let me know why this taking much time
A minor change to the code will affect the total performance. Instead of using Start-Process, you may use the following code:
$buildProcInfo = New-Object -TypeName System.Diagnostics.ProcessStartInfo -ArgumentList "devenv.exe", $buildArgs
try { $buildProcess = [System.Diagnostics.Process]::Start($buildProcInfo) }
catch {
Write-Host "Error"
# exit?
}
$buildProcess.WaitForExit()
Related
$GAMCheck = invoke-command -ScriptBlock { C:\GAMADV-XTD3\GAM.exe version checkrc }
If ($GAMCheck) {
$current = $GAMCheck.split(":")[19].Trim()
$latest = $GAMCheck.split(":")[21].Trim()
If ($LASTEXITCODE -eq 1) {
Try {
$NeedUpGradeCode = $LASTEXITCODE
$client = new-object System.Net.WebClient
$client.DownloadFile("https://github.com/taers232c/GAMADV-XTD3/releases/download/v$latest/GAMadv-xtd3-$latest-windows-x86_64.msi", "C:\Temp\GAMadv-xtd3-$latest-windows-x86_64.msi")
Start-Process -Filepath "C:\Temp\GAMadv-xtd3-$latest-windows-x86_64.msi" -ArgumentList "/passive" | Wait-Process -Timeout 75
Remove-Item "C:\Temp\GAMadv-xtd3-$latest-windows-x86_64.msi"
$GAMCheck = $null
$GAMCheck = invoke-command -ScriptBlock { C:\GAMADV-XTD3\GAM.exe version checkrc }
$newCurrent = $GAMCheck.split(":")[19].Trim()
$resultsarray = [PSCustomObject]#{
CurrentVersion = $current
LatestVersion = $latest
NeedUpgradeCode = $NeedUpGradeCode
Upgraded = $true
NewCurrent = $newCurrent
AfterUpgradeCode = $LASTEXITCODE
}
}
Catch {
Write-Warning "Problem with site or command. Maybe go to https://github.com/taers232c/GAMADV-XTD3/releases and download the current GAM and then install GAM in C:\GAMADV-XTD3\ again"
}
}
}
lately I have been noticing that the | Wait-process 75 above is causing an error.
If I run the command with out it everything is fine.
Is there another way to wait for the install ?
To launch a process with Start-Process and wait for it to exit, use the -Wait switch.
Piping a Start-Process call to Wait-Process would only work as intended if you included the -PassThru switch, which makes Start-Process - which by default produces no output - emit a System.Diagnostics.Process instance representing the newly launched process, on whose termination Wait-Process then waits.
Note that, surprisingly, the behavior of these two seemingly equivalent approaches is not the same, as discussed in GitHub issue #15555.
I am trying to install software (executable) on several servers with various versions of PowerShell.
Normally below code works with no issue on PS4 and up. On PS3 it does not install anything, nor does it produce any errors on the remove server eventviewer. It treated as success by printing out "... -- installation succeeded" and exits. I've googled about and read that perhaps Start-Process is the culprit in PS3.
Begin {
$uncpath="\\remoteserveruncpath\" #"
$exe_parameter1 = "centralserver.com"
$creds = Get-Credential -Message "Password: " -Username "$($env:userdnsdomain)\$($env:username)"
}
Process {
$dnshostname = "server1","server2","server3"
ForEach ($server in $dnshostname) {
Invoke-Command -ComputerName $server -ScriptBlock {
param($server_int,$exe_parameter1_int,$uncpath_int,$creds_int)
(New-Object -ComObject WScript.Network).MapNetworkDrive('Z:',"$($uncpath_int)", $false, "$($creds_int.Username)", "$($creds_int.GetNetworkCredential().Password)")
$arguments = "/param_1=$exe_parameter1_int /param_2=$($server_int.ToLower()) /start-program=1 /S"
If((Start-Process "Z:\installer.exe" -ArgumentList $arguments -Wait -Verb RunAs).ExitCode -ne 0) {
Write-Host "$server_int -- installation succeeded"
} else {
Write-Error "$server_int -- installation failed"
}
} -ArgumentList $server,$exe_parameter1,$uncpath,$creds;
}
}
Any advice? Many thanks!
Without -PassThru, Start-Process produces no output, so accessing .ExitCode effectively returns $null, always.
And since $null -ne 0 is always $true, your code always indicates success.
In order to get the installer command's true exit code, you therefore need to use the following (note the addition of -PassThru):
if ((Start-Process -PassThru 'Z:\installer.exe' -ArgumentList $arguments -Wait -Verb RunAs).ExitCode -ne 0) { ... }
Is there any way to wait for the copy process to finish before running another command?
I tried Start-job and Wait-Job, but it doesn't work.
$func = {
function move-tozip
{
param([string]$filedest)
$Shell = New-Object -com Shell.Application
$b = $shell.namespace($zippath.ToString())
$b.CopyHere($filedest.tostring())
#Remove-Item -Path $filedest
}
}
start-job -InitializationScript $func -ScriptBlock {move-tozip $args[0]} -ArgumentList $file
The easiest way to wait for a job to complete is to give it a name and tell Wait-Job to wait on the task with that name, your script will wait for the job with the name WaitForMe to complete and then run the rest of your code once it has.
Using the -Name paramter with your code below:
$func =
{
function Move-ToZip
{
Param([string[]]$path, [string]$zipfile)
if (-not $zipfile.EndsWith('.zip')) {$zipfile += '.zip'}
if (-not (test-path $zipfile))
{
set-content $zipfile ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
}
$shell = (new-object -com shell.application).NameSpace($zipfile)
foreach($file in $path)
{
$shell.CopyHere($file)
start-sleep -milliseconds 100
}
}
}
Start-Job -Name "WaitForMe" -InitializationScript $func -ScriptBlock {Move-ToZip -path $args[0] -zipfile $args[1]} -ArgumentList "D:\data.log", "D:\datazip.zip"
Write-Host "Waiting for job to complete"
Wait-Job -Name "WaitForMe"
Write-Host "Job has completed :D"
To zip one file or folder
-ArgumentList "D:\testfile.log", "D:\datazip.zip"
To zip multiple files or folders
-ArgumentList #("D:\testfile.log","D:\testFolder1"), "D:\testzip.zip"
EDIT 17/12/2015
I've adapted code from This MSDN blog to the Move-ToZip function as the previous code didnt work for me at all, i've tested the above code successfully on files and folders. I have not tested the performance of this method, if you wish to compress/zip multiple large files/folders i would highly suggest looking into using a known working library or third party utility like 7zip.
I'm trying to specify parameters in a powershell script, from a batch file.
The script itself looks likes this:
Param(
[Parameter(Mandatory=$true,HelpMessage="Application switch")]
[string[]]$Apps,
[ValidateRange(3,9999)]
[int]$SwitchDelay = 30
$AppPids = #()
$Windows = Get-Process | ? { $_.MainWindowTitle -ne "" }
$Wsh = New-Object -COM Wscript.Shell
foreach ($App in $Apps) {
foreach ($Window in $Windows) {
if ($Window.MainWindowTitle -like $App) {
Write-Verbose "Vindusfilter ""$App"" found hit on ""$($Window.MainWindowTitle)"" med PID ""$($Window.Id)"""
$AppPids += $Window.Id
}
}
}
do {
foreach ($ID in $AppPIDS) {
# Hides text...
$Wsh.AppActivate($ID) | Out-Null
Start-Sleep -Seconds $SwitchDelay
Write-Verbose "Changed window to PID ""$ID"""
}
} while ($true)
And what I'm trying to do is to define in a batch file is something like:
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File "C:\AppRotate.ps1" -Apps "*Chrome*", "Spotify*" -Switchdelay 5
pause
(Supposed to show error message here, need more reputation first...)
Error: "... PositionalParameterNotFound.Approtate.ps1"
I'm basically new to scripting, so any ideas?
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File "C:\AppRotate.ps1" -Apps "*Chrome*","Spotify*" -Switchdelay 5
The problem was the space between the first, and second variable of parameter -Apps.
Should work now.
I have a script below that errors when trying to access a file, however if I change the location of the .msi file in the -argumentlist to a full address it succeeds, but I can't have it run like that as the address will change when I submit it to be packaged for SCCM deployment.
Function Get-OSCComputerOU
{
$ComputerName = $env:computername
$Filter = "(&(objectCategory=Computer)(Name=$ComputerName))"
$DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher
$DirectorySearcher.Filter = $Filter
$SearcherPath = $DirectorySearcher.FindOne()
$DistinguishedName = $SearcherPath.GetDirectoryEntry().DistinguishedName
$OUName = ($DistinguishedName.Split(","))[1]
$OUMainName = $OUName.SubString($OUName.IndexOf("=")+1)
$OUMainName
}
$strOU = Get-OSCComputerOU
$strTrueOU=$strOU.split('_')[1]
$strCSV=Import-Csv \\SERVER\SHARE\FOLDER\CSV.csv
$strRoomChannel=$strCSV | where {$_.Room -eq $strTrueOU} | % channel
IF ($strRoomChannel){
$strRoomFoundArg="/i .\Installers\MSI.msi CHANNEL=$strRoomChannel"
Start-Process msiexec -ArgumentList $strRoomFoundArg -wait
} ELSE {
msg * "Channel is missing, and can not install correctly, please call tech support on Ext: to have this rectified, it's a quick fix."
}
When I use a full address such as below, it installs fine.....what's the deal.
Function Get-OSCComputerOU
{
$ComputerName = $env:computername
$Filter = "(&(objectCategory=Computer)(Name=$ComputerName))"
$DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher
$DirectorySearcher.Filter = $Filter
$SearcherPath = $DirectorySearcher.FindOne()
$DistinguishedName = $SearcherPath.GetDirectoryEntry().DistinguishedName
$OUName = ($DistinguishedName.Split(","))[1]
$OUMainName = $OUName.SubString($OUName.IndexOf("=")+1)
$OUMainName
}
$strOU = Get-OSCComputerOU
$strTrueOU=$strOU.split('_')[1]
$strCSV=Import-Csv \\SERVER\SHARE\FOLDER\CSV.csv
$strRoomChannel=$strCSV | where {$_.Room -eq $strTrueOU} | % channel
IF ($strRoomChannel){
$strRoomFoundArg="/i C:\Users\USERNAME\Desktop\Installers\MSI.msi CHANNEL=$strRoomChannel"
Start-Process msiexec -ArgumentList $strRoomFoundArg -wait
} ELSE {
msg * "Channel is missing, and can not install correctly, please call tech support on Ext: to have this rectified, it's a quick fix."
}
I get this error:
The difference between the two is that '.' is going to be resolved by the process you are calling, msiexec, which, like most processes, is going to use the process's CurrentDirectory for '.', which is different than the current location in PowerShell. You can see the difference if you compare Get-Location and [Environment]::CurrentDirectory] in PowerShell. They will be different if you start powershell and change the directory using Set-Location (aka cd).
The solution is to resolve the path in PowerShell before sending it over to msiexec:
$path = Convert-Path .\Installers\MSI.msi
$strRoomFoundArg = "/i `"$path`" CHANNEL=$strRoomChannel"
Start-Process msiexec -ArgumentList $strRoomFoundArg -wait
Turns out the script wasn't happy with the .\ in front of the MSI file.
If I kept the .\ I would get the error.
If I removed the .\ and just had MSI.msi then it worked fine.
I failed to mention that I had changed the active directory to my desktop to execute the script, my apologies #mike z
Thank you very much for your input however.