Need Help crating powershell Install script

Mike
Mike used Ask the Experts™
on
Greeting Experts -

Need help setting up a PowerShell script to install a piece of client software (WindowsSensor.exe) on the list of computers. Can somebody help me write a script that will prompt me for my Admin Credentials, copy the software from a file directory (source file) to folder on the local computer, and then start the install from the command line using these install arguments

software:  WindowsSensor.exe
CLI Install arguments:  WindowsSensor.exe /install /quiet /norestart CID=InstallToken
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Darrell PorterEnterprise Business Process Architect

Commented:
param (
    [Parameter(Mandatory=$true)][string]$username,
    [Parameter(Mandatory=$true)][string]$password
)


#$machineArray = import-csv "d:\Files\ListOfComputers.csv"

$script = $MyInvocation.MyCommand.Definition
$scriptname = [io.path]::GetFileNameWithoutExtension($(Split-Path $script -Leaf))

$runlog = Get-Date -Format yyyyMMddHHmm
# If the folder for this script's logs doesn't exist, make it!
If (-not(Test-Path "D:\Logs\$Scriptname" -PathType Container)) { New-Item -ItemType directory -Path "D:\Logs\$Scriptname" }
$logfile = (-join("D:\Logs\\",$scriptname,"\\",$scriptname,"-",$runlog,".log"))
$nl = [Environment]::NewLine

$init = {

    function Do-Work ($machinename $username $password) {
        filter timestamp {"$(Get-Date -Format G): $_"}
        $runday = Get-Date -Format "yyyyMMddHHmm"
        # check if the store answers ping first
        $ans = Test-Connection -ComputerName $machinename -count 1 -quiet
  
        if ($ans) {
            Write-Output (('---------------------------------------')|timestamp)
            # Insert work here at 3 indentations (12 spaces) from Left margin
            $MachinePath = "\\$machinename\C$\Temp"
            $secCred = SecureCredentials $username $password
            New-PSDrive -Name TMP -PSProvider FileSystem -Root $MachinePath -Credential $secCred | Out-Null
            #Test drive map
            if (Test-Path -Path $MachinePath) {
                if (!(Test-Path -Path "$MachinePath\WindowsSensor.exe")) {
                    Log "Cannot locate WindowsSensor Installer on $machinename; cannot install WindowsSensor."
                    return $false
                }
                Else {
                    &$PathToPSExec.EXE -s \\$machinename C:\Temp\WindowsSensor.exe  /install /quiet /l*v:c:\temp\WindowsSensorMSIInstall.log /norestart CID=InstallToken 2>&1>C:\Temp\WindowsSensorPSExec.log
                }
            }
        }
        else {
            write-output ''
            write-output (('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')|timestamp)
            write-output (($machinename + ' offline!')|timestamp)
            write-output (('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')|timestamp)
            write-output ''
        }

        
    }

}


function ExitWithCode 
{
    param 
    ( 
        $exitcode 
    )

    $host.SetShouldExit($exitcode) 
    exit 
}

#

if (Test-Path $logfile) {
    Remove-Item $logfile
}

Remove-Job *

$queueLimit = 100
$counter = 0
$totalCycles = $storearray.count

foreach ($machine in $machinearray | Sort 'Machine Name') {
    $machinename = $machine.'Machine Name'
    $counter += 1
    write-host "Processing cycle $counter out of $totalCycles" -ForegroundColor Green
    $running = @(Get-Job | Where-Object {$_.State -eq "Running"})
    Write-Host 'Job queue length is ' $running.count -ForegroundColor Yellow
    if ($running.Count -ge $queueLimit) {
        write-host "Waiting for spot in queue" -ForegroundColor Green
        $running | Wait-Job -Any | Out-Null
    }
    write-output "Starting Job for computer $($machinename)"
    # Start jobs here
    Start-Job -InitializationScript $init -ArgumentList $($machinename), $username, $password -ScriptBlock {Do-Work $args[0] $args[1] $args[2]} -Name $($machinename) | Out-Null
    write-host ""
}

write-host ""
write-host "Waiting for remaining jobs to complete" -ForegroundColor Green

$runcount = (@(Get-Job | Where-Object {$_.State -eq "Running"})).count
$runcount
Do {
    $running = @(Get-Job | Where-Object {$_.State -eq "Running"})
    If ($running.count -lt $runcount){
        $runcount = $running.count
        $runcount
    }
}
While ($running.count -gt 0)

Get-Job | Wait-Job
write-host ""
write-host "Done" -ForegroundColor Green

foreach ($job in get-job) {
    Receive-Job -Job $job -Keep | out-file $logfile -Append
    "-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-" | out-file $logfile -Append
}
$inFile   = $logfile


$sendTo = @('username@domain.com') # This is for script testing only
$sendFrom = “Script Reporting <noreply@domain.com>"
$smtp = 'smtp.domain.com'
$port = '25'
$subject = "Log for WindowsSensor Installation $runday"
$content = Get-Content $inFile | Out-String
$content = [string]::Join("`n",$content)
Send-MailMessage -To $sendTo -From $sendFrom -Subject $subject -Body $content -SmtpServer $smtp -Port $port

Open in new window

This should be close.  Look at the end and, if your Exchange/SMTP mail server won't allow relaying, simply delete the last 9 lines.
This should prompt you for your credentials then run the script in parallel against a provided CSV file of machine names.  The column header for the Machine Name field MUST be "Machine Name" unless you choose to modify the code.
MikeSecurity

Author

Commented:
I getting the following error message below... Do you have any idea's  


Exception calling "GetFileNameWithoutExtension" with "1" argument(s): "Illegal characters in path."
At line:10 char:56
+ $scriptname = [io.path]::GetFileNameWithoutExtension($(Split-Path $script -Leaf) ...
+                                                        ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentException

Open in new window

Top Expert 2016
Commented:
you have to save the script.. there are some illegal characters in the script
$machinarray is never called
param (
  [Parameter(Mandatory = $true)][string]$username,
  [Parameter(Mandatory = $true)][string]$password,
  [Parameter(Mandatory = $true)][string]$csvpath = 'd:\logs\ListofComputers.csv',
  [string]$logpath = 'd:\logs'
)


$machineArray = Import-Csv $csvpath

$script = $MyInvocation.MyCommand.Definition
$scriptname = [io.path]::GetFileNameWithoutExtension($(Split-Path -Path $script -Leaf))
$runlog = Get-Date -Format yyyyMMddHHmm
# If the folder for this script's logs doesn't exist, make it!
If (-not(Test-Path -Path "$logpath\$scriptname" -PathType Container)) 
{
  New-Item -ItemType directory -Path "$logpath\$scriptname" 
}
$logfile = (-join(('{0}\' -f $logpath), $scriptname, '\\', $scriptname, '-', $runlog, '.log'))
$nl = [Environment]::NewLine

$init = {
  foreach($machinename in $machineArray.machinename) 
  {
    #   filter timestamp {"$(Get-Date -Format G): $_"}
    $runday = Get-Date -Format 'yyyyMMddHHmm'
        
    # check if the store answers ping first
    $ans = Test-Connection -ComputerName $machinename -Count 1 -Quiet
  
    if ($ans) 
    {
      Write-Output -InputObject (('---------------------------------------')|timestamp)
      # Insert work here at 3 indentations (12 spaces) from Left margin
      $MachinePath = "\\$machinename\C$\Temp"
      $secCred = SecureCredentials $username $password
      $null = New-PSDrive -Name TMP -PSProvider FileSystem -Root $MachinePath -Credential $secCred
      #Test drive map
      if (Test-Path -Path $MachinePath) 
      {
        if (!(Test-Path -Path "$MachinePath\WindowsSensor.exe")) 
        {
          Log "Cannot locate WindowsSensor Installer on $machinename; cannot install WindowsSensor."
          return $false
        }
        Else 
        {
          &$PathToPSExec.EXE -s \\$machinename C:\Temp\WindowsSensor.exe  /install /quiet /l*v:c:\temp\WindowsSensorMSIInstall.log /norestart CID=InstallToken 2>&1>C:\Temp\WindowsSensorPSExec.log
        }
      }
    }
    else 
    {
      Write-Output -InputObject ''
      Write-Output -InputObject (('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')|timestamp)
      Write-Output -InputObject (($machinename + ' offline!')|timestamp)
      Write-Output -InputObject (('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')|timestamp)
      Write-Output -InputObject ''
    }
  }
}


function Exit-WithCode 
{
  param 
  ( 
    $exitcode 
  )

  $host.SetShouldExit($exitcode) 
  exit 
}

#

if (Test-Path $logfile) 
{
  Remove-Item $logfile
}

Remove-Job -Name *

$queueLimit = 100
$counter = 0
$totalCycles = $storearray.count

foreach ($machine in $machineArray | Sort-Object -Property 'Machine Name') 
{
  $machinename = $machine.'Machine Name'
  $counter += 1
  Write-Host "Processing cycle $counter out of $totalCycles" -ForegroundColor Green
  $running = @(Get-Job | Where-Object -FilterScript {
      $_.State -eq 'Running'
  })
  Write-Host 'Job queue length is ' $running.count -ForegroundColor Yellow
  if ($running.Count -ge $queueLimit) 
  {
    Write-Host 'Waiting for spot in queue' -ForegroundColor Green
    $null = $running |
    Wait-Job -Any
  }
  Write-Output -InputObject "Starting Job for computer $($machinename)"
  # Start jobs here
  $null = Start-Job -InitializationScript $init -ArgumentList $($machinename), $username, $password -ScriptBlock {
    Do-Work $args[0] $args[1] $args[2]
  } -Name $($machinename)
  Write-Host ''
}

Write-Host ''
Write-Host 'Waiting for remaining jobs to complete' -ForegroundColor Green

$runcount = (@(Get-Job | Where-Object -FilterScript {
      $_.State -eq 'Running'
})).count
$runcount
Do 
{
  $running = @(Get-Job | Where-Object -FilterScript {
      $_.State -eq 'Running'
  })
  If ($running.count -lt $runcount)
  {
    $runcount = $running.count
    $runcount
  }
}
While ($running.count -gt 0)

Get-Job | Wait-Job
Write-Host ''
Write-Host 'Done' -ForegroundColor Green

foreach ($job in Get-Job) 
{
  Receive-Job -Job $job -Keep | Out-File $logfile -Append
  '-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-' | Out-File $logfile -Append
}
$inFile   = $logfile
<#
    #region email

    $sendTo = @('username@domain.com') # This is for script testing only
    $sendFrom = "Script Reporting <noreply@domain.com>"
    $smtp = 'smtp.domain.com'
    $port = '25'
    $subject = "Log for WindowsSensor Installation $runday"
    $content = Get-Content $inFile | Out-String
    $content = [string]::Join("`n",$content)
    Send-MailMessage -To $sendTo -From $sendFrom -Subject $subject -Body $content -SmtpServer $smtp -Port $port
    #endregion email
#>

Open in new window

HTML5 and CSS3 Fundamentals

Build a website from the ground up by first learning the fundamentals of HTML5 and CSS3, the two popular programming languages used to present content online. HTML deals with fonts, colors, graphics, and hyperlinks, while CSS describes how HTML elements are to be displayed.

Darrell PorterEnterprise Business Process Architect

Commented:
David, $machinearray is called on line 80 of my script and should never be called within the $init scriptblock.

The error in line 10 is generated because the script presumes it has been saved and not merely in the editor of ISE.  Save the script somewhere and change the appropriate values for the name of the file containing the computer names in line 7.

Mike, what is your level of Powershell proficiency?  If you are not proficient, I can provide you with a commented copy of the code.
I use a framework I wrote in Powershell to perform parallel execution across hundreds of sites simultaneously and that is what I used for this script.
MikeSecurity

Author

Commented:
I am new to PS... I know how to write a simple script... but nothing to the level of this one.
MikeSecurity

Author

Commented:
Thanks, the script worked
MikeSecurity

Author

Commented:
Thanks for the help
Darrell PorterEnterprise Business Process Architect
I find it a bit odd that I did not receive even partial credit as your solution originated from my script.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial