As picture below, when I am checking"Properties" for any user defined Data Collector sets (Performance Monitor), I can see a "Directory" tab which refers the Path for it.
Is there any C# code or powershell script or any other way to get the same path by just providing user defined Data Collector sets name? Thanks!
Below is the Powershell code you can use just change the path in the code and data collectors as per your need it will automatically start the performance data collector with given process name in the code
first if code is just to bypass the script execution policy in the powershell for any host machine and run the script with the admin rights you can remove that if script execution is enabled
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs;}
Param(
[string]$name = "Test"
)
$datacollectorset = New-Object -COM Pla.DataCollectorSet
$datacollectorset.DisplayName = $name;
$datacollectorset.Duration = 14400 ;
$datacollectorset.SubdirectoryFormat = 1 ;
$datacollectorset.SubdirectoryFormatPattern = "yyyy\-MM";
$datacollectorset.RootPath = "%systemdrive%\PerfLogs\Admin\" + $name ;
$DataCollector = $datacollectorset.DataCollectors.CreateDataCollector(0)
$DataCollector.FileName = $name + "_";
$DataCollector.FileNameFormat = 0x1 ;
$DataCollector.FileNameFormatPattern = "yyyy\-MM\-dd";
$DataCollector.SampleInterval = 10
$counters = #(
"\Memory\Available MBytes",
"\Memory\Page Faults/sec",
"\Memory\Page Reads/sec",
"\Memory\Page Writes/sec",
"\Memory\Pages Input/sec",
"\Memory\Pages Output/sec",
"\Process(CloudHASHService)\*",
"\Processor(_Total)\% Idle Time",
"\Processor(_Total)\% Interrupt Time",
"\Processor(_Total)\% Privileged Time",
"\Processor(_Total)\% Processor Time",
"\Processor(_Total)\% User Time"
) ;
$DataCollector.PerformanceCounters = $counters
try
{
$datacollectorset.DataCollectors.Add($DataCollector)
$datacollectorset.Commit("$name" , $null , 0x0003) | Out-Null
$datacollectorset.Start($false);
}
catch [Exception]
{
Write-Host "Exception Caught: " $_.Exception -ForegroundColor Red
return
}
Related
I have a powershell script which runs an exe and get its output which is working fine, but the issue that i am facing is that if the process is already running then it is not able to capture the output.
Below is my code
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "E:\Program Files (x86)\Consul_Ent\Bin\consul.exe"
$pinfo.Arguments = "agent -config-dir E:\Consul_Ent\Configuration\Client"
$pinfo.UseShellExecute = $false
$pinfo.CreateNoWindow = $false
$pinfo.RedirectStandardInput = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.RedirectStandardError = $true
$pinfo.EnvironmentVariables["GOMAXPROCS"] = (Get-WmiObject Win32_Processor | measure -p NumberOfLogicalProcessors -sum).Sum
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $pinfo
[Void]$process.Start()
$process.BeginOutputReadLine()
$process.BeginErrorReadLine()
try
{
while (!$process.WaitForExit(1))
{
}
Write-Host "WaitForExit(1)"
}
finally
{
# give the thread gracefully shutdown
Start-Sleep -s 3
}
so as the process is not terminated yet and hence it is not able to read the output as it tries to create a new instance, i want it to create a new instance only if process is not running but if it is running i just want to capture the output.
I want to execute a powershell script via winforms and get well-formatted output. I managed to get it to work but now I need to pass parameters to my script. I can't manage to make that happen.
Here is my RunScript function :
private string RunScript(string scriptFile)
{
Runspace runSpace = RunspaceFactory.CreateRunspace();
runSpace.Open();
Pipeline pipeLine = runSpace.CreatePipeline();
Command script = new Command(scriptFile);
script.Parameters.Add("COM_USERNAME", usernameBox.Text);
script.Parameters.Add("COM_PASSWORD", passwordBox.Text);
script.Parameters.Add("installDir", installDirBox.Text);
script.Parameters.Add("TEMPVAULT_PATH", tempVaultBox.Text);
script.Parameters.Add("MAX_REQ_LIMIT", maxReqLimBox.Text);
script.Parameters.Add("MAX_BUFF_LIMIT", maxBuffLimBox.Text);
pipeLine.Commands.AddScript(script.ToString());
pipeLine.Commands.Add("Out-String");
Collection<PSObject> results = pipeLine.Invoke();
runSpace.Close();
StringBuilder strBuilder = new StringBuilder();
foreach (PSObject item in results)
{
strBuilder.AppendLine(item.ToString());
}
return strBuilder.ToString();
}
And this is the script that I am trying with:
param (
[bool] $STARTSERVICE = $false ,
[bool] $INSTALL = $false ,
[bool] $INSTALL_DASHBOARD = $false,
[bool] $DASHBOARD_SETTINGS = $false,
[bool] $DASHBOARD_CREATENEWDB = $false,
[bool] $DALIM_SETTINGS = $false,
[bool] $INSTALLIIS = $true,
[bool] $FIRST_INSTALL = $true,
[bool] $RECOVERY = $false,
[string] $COM_USERNAME,
[string] $COM_PASSWORD,
[string] $RECOVERY_ADM_NAME,
[string] $RECOVERY_ADM_PWD,
[string] $Windows2012DVDLetter = "F:",
[string] $COM_UNCPATH,
[string] $installDir = "C:\Program Files\App\",
[string] $TEMPVAULT_PATH = "C:\TempVault",
$SOAP_MaxPostSize = 4294967295,
$MAX_REQ_LIMIT = 500000000,
$MAX_BUFF_LIMIT = 500000000
)
Write-Output "`nUsername = " $COM_USERNAME
Write-Output "`nPassword = " $COM_PASSWORD
Write-Output "`nCOM_UNCPATH = " $COM_UNCPATH
Write-Output "`nMaximum Request Limit = " $MAX_REQ_LIMIT
Write-Output "`nMaximum Buff Limit = " $MAX_BUFF_LIMIT
Write-Output "`nIsFirstInstall = " $FIRST_INSTALL
Write-Output "`nInstallation Directory = " $installDir
Write-Output "`nTempVault Path = " $TEMPVAULT_PATH
Write-Output "`nRestriction level = " $RESTRICT_LVL
I have output with only the pre-registered in the script values showing, but the ones I'm trying to show (textboxes inputs) don't. Have I missed something?
Note: The following assumes that scriptFile is the path of a *.ps1 file, not that file's content (a string containing Powershell code).
See the bottom section for how to handle the latter case.
You can greatly simplify your invocation:
private string RunScript(string scriptFile)
{
using (var ps = PowerShell.Create()) {
ps.AddCommand(scriptFile) // Be sure to pass a *full path*
.AddParameter("COM_USERNAME", usernameBox.Text)
.AddParameter("COM_PASSWORD", passwordBox.Text)
.AddParameter("installDir", installDirBox.Text)
.AddParameter("TEMPVAULT_PATH", tempVaultBox.Text)
.AddParameter("MAX_REQ_LIMIT", maxReqLimBox.Text)
.AddParameter("MAX_BUFF_LIMIT", maxBuffLimBox.Text)
.AddCommand('Out-String'); // Add a pipeline segment
// Return the 1st (and in this case only) output object, as a string.
return ps.Invoke<string>()[0];
}
}
Using PowerShell.Create() creates an instance of class PowerShell, which provides a higher-level API based on an implicitly created runspace:
Methods can be chained.
Calling .AddCommand() repeatedly automatically adds new pipeline segments.
As for what you tried:
pipeLine.Commands.AddScript(script.ToString());
The .AddScript() method is for adding arbitrary pieces of PowerShell code, not for adding Command instances with associated parameters.
(Command instances represent either a PowerShell command such as Out-String or the name / path of an external executable or the path[1] to a script file (*.ps1)).
By stringifying the Command instance stored in script with .ToString(), you're effectively just passing the script path as the command to execute - all the parameters you've added with .AddParameter() are lost, which is why you only saw the default parameter values in the script's output.
Instead, you should have added your Command instance as follows:
pipeLine.Commands.Add(script)
If scriptFile is not a file path, but the contents of a script file (a string containing PowerShell code):
As you've since clarified, this is your actual use case, because the script is embedded as a resource in your executable that you pass with RunScript(Properties.Resources.<the script>)
Adapt the simplified approach at the top as follows:
// If `scriptFile` is the *contents* of a *.ps1 file,
// add it as a script [block] with .AddScript(),
// then add parameters (and the additional pipeline command).
ps.AddScript(scriptFile)
.AddParameter("COM_USERNAME", usernameBox.Text)
.AddParameter("COM_PASSWORD", passwordBox.Text)
.AddParameter("installDir", installDirBox.Text)
.AddParameter("TEMPVAULT_PATH", tempVaultBox.Text)
.AddParameter("MAX_REQ_LIMIT", maxReqLimBox.Text)
.AddParameter("MAX_BUFF_LIMIT", maxBuffLimBox.Text)
.AddCommand('Out-String'); // Add a pipeline segment
[1] PowerShell only allows by-name-only executions (e.g., foo.ps1) for executables / scripts located in a directory listed in the PATH environment variable. Otherwise, a file path must be specified, and it's safest to use a full path, because .NET's current directory usually differs from PowerShell's.
I am calling my exe from powershell script like shown below.
$file = $PSScriptRoot + "\executor.exe"
$code = (Start-Process -WindowStyle Hidden $file -Verb runAs -ArgumentList $Logfile).StandardOutput.ToString;
$nid = (Get-Process "executor.exe").id
Wait-Process -Id $nid
if ($code -eq 1) {
LogWrite "Execution succeeded"
} else
{
LogWrite "Execution Failed"
}
I have a int main function in my exe program which would return 1 on success, and 0 on failure.
When i try to get the ExitCode(using $LASTEXITCODE) from powershell script it always shows null(neither 1 nor 0), But my exe is returning 1 as expected.
How do i capture the return value of exe in powershell script?
You can use this:
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = # path to your exe file
# additional options:
$psi.UseShellExecute = $false
$psi.CreateNoWindow = $false
$psi.WindowStyle = "Maximized"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null # returns $true if the process started, $false otherwise
$p.WaitForExit()
# here's the exitcode
$exitCode = $p.ExitCode
Create the process start info, to specify the executable path, and additional options. It's important to use .WaitForExit() to wait until the process finishes.
What you have tried doesn't get the app exitcode, but what the application write to standard console, which, in your case, I assume is nothing. If you could modify the exe to write to the console, what you did would work.
I would like to ask how to prevent shutdown, when running a script or at least give a popup that will ask whenever or not you want to shutdown (like when you open a notepad and write a char, but doesn't save it and the click shutdown).
I have been creating scripts that runs installers silent, but some of them still seems to activate windows shutdown (this can happen if they are missing prerequisites).
Here is the code I use for the installation:
# --- Install ---
$fileExtension = (Get-ChildItem -path $installationFilePath).Extension
if(".msi" -eq $fileExtension)
{
[string[]]$Private:args = New-Object string[] 4
$args[0] = "/qn"
$args[1] = "TRANSFORM=1033.mst"
$args[2] = "REBOOT=Suppress"
$args[3] = "/l*v $errorLogPath"
$process = Start-Process $installationFilePath -ArgumentList $args -PassThru
}
if(".exe" -eq $fileExtension)
{
[string[]]$Private:args = New-Object string[] 2
$args[0] = '/v"' + "/qn TRANSFORM=1033.mst REBOOT=Suppress /l*v $errorLogPath" + '"'
$args[1] = "/s"
$process = Start-Process $installationFilePath -ArgumentList $args -PassThru
}
$processActive = $process
while ($processActive -ne $null)
{
Start-Sleep -Seconds 1
Write-Host '.' -NoNewline
$processActive = Get-Process -Id $processActive.Id -ErrorAction SilentlyContinue
}
I know this should be possible, but I have yet to find out how.
Here is an example of aborting shutdown after the install has finished:
Start-Process yourprogram.exe -Wait
shutdown /a
You could even loop the abort a few times to make sure you hit it.
for($i=0;$i -lt 5;$i++)
{
shutdown /a
sleep 1
}
I am trying to replicate this Self-Elevating script in Powershell, but as a function instead of as an entire script so to break up the code for better flow. The original code can be found here.
http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/09/23/a-self-elevating-powershell-script.aspx
However, when I rewrite the same code as a function, it errors out dramatically. Any idea what is causing the fault? This is the new, erroneous code.
function SelfElevation
{
# Get the ID and security principal of the current user account
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal ($myWindowsID)
# Get the security principal for the Administrator role
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
# Check to see if we are currently running "as Administrator"
if ($myWindowsPrincipal.IsInRole($adminRole))
{
# We are running "as Administrator" - so change the title and background color to indicate this
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
$Host.UI.RawUI.BackgroundColor = "DarkBlue"
$Host.UI.RawUI.ForegroundColor = "White"
clear-host
}
else
{
# We are not running "as Administrator" - so relaunch as administrator
# Create a new process object that starts PowerShell
$newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
# Specify the current script path and name as a parameter
$newProcess.Arguments = $myInvocation.MyCommand.Definition;
# Indicate that the process should be elevated
$newProcess.Verb = "runas";
# Start the new process
[System.Diagnostics.Process]::Start($newProcess)
# Exit from the current, unelevated, process
Stop-Process -Id $PID
}
}
# We call the self elevation here
SelfElevation
# Run your code that needs to be elevated here
Write-Host -NoNewLine "Press any key to continue..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
This code works fine as I truncate it, right up until the part where it hits Start $newProcess, and it simply does not seem to like the new process being executed in a function. However, why?
Thank you in advance for your time!
The arguments your script takes is likely to be slightly different than what Powershell.exe takes. Try this approach:
[string[]]$argList = #('-NoProfile', '-NoExit', '-File', $MyInvocation.MyCommand.Path)
$argList += $MyInvocation.BoundParameters.GetEnumerator() | Foreach {"-$($_.Key)", "$($_.Value)"}
$argList += $MyInvocation.UnboundArguments
Start-Process PowerShell.exe -Verb Runas -WorkingDirectory $pwd -ArgumentList $argList
Fix for "white spaces in path" problem and also additional code to set new powershell process path to actual script location
And another fix of error when script is located at mapped network drive
#region Self-Elevating
Set-Location ( Get-Item $script:MyInvocation.MyCommand.Path ).Directory
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal = new-object System.Security.Principal.WindowsPrincipal( $myWindowsID )
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator
if ( !$myWindowsPrincipal.IsInRole( $adminRole )) {
# This fixes error wen script is located at mapped network drive
$private:scriptFullPath = $script:MyInvocation.MyCommand.Path
if ( $scriptFullPath.Contains([io.path]::VolumeSeparatorChar )) { # check for a drive letter
$private:psDrive = Get-PSDrive -Name $scriptFullPath.Substring(0,1) -PSProvider 'FileSystem'
if ( $psDrive.DisplayRoot ) { # check if it's a mapped network drive
$scriptFullPath = $scriptFullPath.Replace( $psdrive.Name + [io.path]::VolumeSeparatorChar, $psDrive.DisplayRoot )
}
}
[string[]]$argList = #( '-NoLogo', '-NoProfile', '-NoExit', '-File', "`"$scriptFullPath`"" )
$argList += $MyInvocation.BoundParameters.GetEnumerator() | % { "-$( $_.Key )", "$( $_.Value )" }
$argList += $MyInvocation.UnboundArguments
Start-Process PowerShell.exe -Verb Runas -WorkingDirectory $PWD -ArgumentList $argList -PassThru
Stop-Process $PID
}
#endregion
Thanks Keith Hill and Randy in Marin