Hi to all I want to call in C# a powershell script. Inside ps1 file I have implemented a function.
Powershell script:
Add-Type -path 'C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll'
Add-Type -path 'C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll'
#$CourseName = Read-host "Enter site name"
CreateBlogSubsite($SiteName)
Function CreateBlogSubsite($SiteName)
{
$user = "johndoe#tenant.onmicrosoft.com";
$pass = "P3003ksi434!";
$secpw = $pass | ConvertTo-SecureString -AsPlainText -Force
$SiteURL = "https://tenant.sharepoint.com/sites/SalesSite/"
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL);
$Creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($user,$secpw);
$Context.Credentials = $Creds;
Try {
#Specify Subsite details
$WebCI = New-Object Microsoft.SharePoint.Client.WebCreationInformation
$WebCI.Title = $SiteName + " Blog" # sitename
$WebCI.WebTemplate = "Blog#0" #Blog Site #site template
$WebCI.Url = $SiteName + "_Blog"
$SubWeb = $Context.Web.Webs.Add($WebCI)
$Context.ExecuteQuery()
$URI = $SiteURL + $WebCI.Url
return $URI
#Write-host "Subsite Created Successfully! Url is: " + $SiteName + "1Blog" -ForegroundColor Green
}
catch {
write-host "Error: $($_.Exception.Message)" -foregroundcolor Red
}
}
Here is my console program, where I call PS script:
static void Main(string[] args)
{
// Execute powershell script
// Initialize PowerShell engine
var shell = PowerShell.Create();
//Add the script via a pre-made ps1 file
shell.Commands.AddScript(#"C:\\Users\\zeb\\source\\CreateCourseBlog.ps1");
shell.Commands.AddParameter("$SiteName", "Desti");
// Execute the script
var results = shell.Invoke(); // I want to get output of Poweshell function
Console.Write(results);
}
But it does not works :( . So, does not create subsite when I call script from c#
This should work:
Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
using (PowerShell ps = PowerShell.Create())
{
ps.Runspace = rs;
ps.AddScript($#"C:\Users\zeb\source\CreateCourseBlog.ps1 -SiteName Desti");
ps.AddCommand("Out-String");
var psOutput = ps.Invoke();
foreach (var item in psOutput)
{
if (item == null) continue;
Console.WriteLine(item.BaseObject.ToString());
}
if (ps.Streams.Error.Count > 0)
Console.WriteLine($"Errors ({ps.Streams.Error.Count}):\n");
foreach (var err in ps.Streams.Error)
Console.WriteLine(" - " + err);
}
In addition to this code you should add next code to the top of your powershell script:
Param(
[string] $SiteName
)
I have successfully:
Created an Azure App Service
Registered it with AAD
Added a certificate to the application manifest using New-AzureADApplicationKeyCredential.
The customKeyIdentifier is set as follows:
[Convert]::ToBase64String($global:CertificateInfo.Certificate.GetCertHash()) ;
Accessed the App Service using the certificate to get an access token via AcquireTokenAsync.
While attempting to write Powershell to make it easier to add certificates to applications, I noticed that you can add an unlimited number of duplicate certificates. What I mean is that they all have a unique keyId but the same
customKeyIdentifier. So I wrote the following code to eliminate creating duplicates
if ($global:CertificateInfo.Certificate -eq $null)
{
throw "No certificate has been selected or created yet."
}
$filter = "DisplayName eq '" + $($DisplayName) + "'" ;
$global:CertificateInfo.Application = Get-AzureADApplication -filter $filter
$certificateThumbprint = [System.Convert]::ToBase64String($global:CertificateInfo.Certificate.GetCertHash()) ;
foreach($keyCredential in $global:CertificateInfo.Application.KeyCredentials)
{
[String]$keyCredentialThumbPrint = [System.Convert]::ToBase64String($keyCredential.CustomkeyIdentifier) ;
if([String]::Equals($keyCredentialThumbPrint,$certificateThumbprint,[StringComparison]::CurrentCultureIgnoreCase)) {
throw "This certificate already exists within the keyCredentials collection with KeyId" + "'" + $keyCredential.KeyId + "'" ;
}
}
The code does not work because the customKeyIdentifier saved in the application manifest is modified somehow by Azure when it is saved so my duplication check fails. Does anyone know how Azure is modifying the customKeyIdentifier so that I can get my duplicate check to work?
Below is a copy of the duplicates that can show up in your application manifest
"keyCredentials": [
{
"customKeyIdentifier": "N0l6V0gxM3phNGxvUUk2UnZNdFE0dWV3aDFnPQ==",
"endDate": "2019-12-18T19:22:10Z",
"keyId": "6bef2fd1-b163-44fd-8f70-90828a6003ef",
"startDate": "2017-12-18T23:05:28.4976081Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": null
},
{
"customKeyIdentifier": "N0l6V0gxM3phNGxvUUk2UnZNdFE0dWV3aDFnPQ==",
"endDate": "2019-12-18T19:22:10Z",
"keyId": "d73d0903-d86f-4277-bbe9-e1cea078b400",
"startDate": "2017-12-18T21:30:05.8419846Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": null
}
So that people better understand that the issue is in using the New-AzureADApplicationKeyCredential cmdlet and not in the duplicate compare logic I have included the Powershell code I am using below
$global:CertificateInfo = #{} ;
function Connect-Azure {
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[string] $TenantId
)
Write-Host "Connect-Azure - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters"
Write-Host " TenantId - $($TenantId)"
$ErrorActionPreference = 'Stop';
Connect-AzureAD -TenantId $TenantId
Write-Host "Connect-Azure - Exit - $($MyInvocation.MyCommand.Name)"
}
function Add-AzureADApplicationKeyCredential {
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[string] $DisplayName,
[parameter(Mandatory=$false)]
[Switch] $Force
)
Write-Host "Add-AzureADApplicationKeyCredential - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Add-AzureADApplicationKeyCredential - Parameters"
Write-Host " DisplayName - $($DisplayName)"
$ErrorActionPreference = 'Stop';
if ($global:CertificateInfo.Certificate -eq $null)
{
throw "No certificate has been selected or created yet."
}
$filter = "DisplayName eq '" + $($DisplayName) + "'" ;
$global:CertificateInfo.Application = Get-AzureADApplication -filter $filter
$certificateThumbprint = [System.Convert]::ToBase64String($global:CertificateInfo.Certificate.GetCertHash()) ;
foreach($keyCredential in $global:CertificateInfo.Application.KeyCredentials)
{
[String]$keyCredentialThumbPrint = [System.Convert]::ToBase64String($keyCredential.CustomkeyIdentifier) ;
if([String]::Equals($keyCredentialThumbPrint,$certificateThumbprint,[StringComparison]::CurrentCultureIgnoreCase)) {
throw "This certificate already exists within the keyCredentials collection with KeyId" + "'" + $keyCredential.KeyId + "'" ;
}
}
$CertificateInfo = #{} ;
$CertificateInfo.CustomKeyIdentifier = [Convert]::ToBase64String($global:CertificateInfo.Certificate.GetCertHash()) ;
$CertificateInfo.Value = [System.Convert]::ToBase64String($global:CertificateInfo.Certificate.GetRawCertData()) ;
$CertificateInfo.EndDate = $global:CertificateInfo.Certificate.NotAfter ;
$CertificateInfo.Type = "AsymmetricX509Cert"
$CertificateInfo.Usage = "Verify" ;
$CertificateInfo.ObjectId = $global:CertificateInfo.Application.ObjectId ;
New-AzureADApplicationKeyCredential #CertificateInfo;
Write-Host "Add-AzureADApplicationKeyCredential - Exit"
}
function Select-Certificate {
[CmdletBinding()]
param
(
[parameter(Mandatory=$false)]
[string] $CertStoreLocation = "Cert:\LocalMachine\My",
[parameter(Mandatory=$true)]
[string] $ThumbPrint
)
Write-Host "Create-SelfSignedCertificate - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters" $ErrorActionPreference = 'Stop';
$certificateLocation = $CertStoreLocation + "\" + $ThumbPrint ;
$global:CertificateInfo.Certificate = (Get-ChildItem –Path "$($certificateLocation)")
}
function Create-SelfSignedCertificate {
[CmdletBinding()]
param
(
[parameter(Mandatory=$false)]
[string] $Subject,
[parameter(Mandatory=$false)]
[string] $HashAlgorithm = "SHA256",
[parameter(Mandatory=$false)]
[string] $CertStoreLocation = "Cert:\LocalMachine\My",
[parameter(Mandatory=$true)]
$NotAfter
)
## see https://blogs.technet.microsoft.com/scotts-it-blog/2014/12/30/working-with-certificates-in-powershell/
Write-Host "Create-SelfSignedCertificate - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters"
if([string]::IsNullOrEmpty($Subject)) {
$currentDate = (Get-Date) ;
$Subject = [String]::Format("SelfSigned{0:yyyymmddHHMMss}",$currentDate) ;
}
Write-Host " Subject - $($Subject)"
Write-Host " HashAlgorithm - $($HashAlgorithm)"
Write-Host " CertStoreLocation - $($CertStoreLocation)"
Write-Host " NotAfter - $($NotAfter)"
$ErrorActionPreference = 'Stop';
Write-Host "Create-SelfSignedCertificate - Exit - $($MyInvocation.MyCommand.Name)"
$SaveChooser = New-Object -Typename System.Windows.Forms.SaveFileDialog
$SaveChooser.CreatePrompt = $false ;
$SaveChooser.Title = "Save certficate" ;
$SaveChooser.DefaultExt = "pfx" ;
$dialogResult = $SaveChooser.ShowDialog()
if($dialogResult -eq [System.Windows.Forms.DialogResult]::Cancel) {
return ;
}
$CertificatePath = $SaveChooser.Filename ;
$certificatePassword = Read-host "Please provide a password for the exported certificate." -AsSecureString
$certParameters = #{} ;
$certParameters.CertStoreLocation = $CertStoreLocation;
$certParameters.Subject = $Subject;
$certParameters.KeySpec = "KeyExchange";
$certParameters.HashAlgorithm = $HashAlgorithm;
$certParameters.CertStoreLocation = $CertStoreLocation;
if ($NotAfter -ne $null) {
$certParameters.NotAfter = $NotAfter;
}
$global:CertificateInfo.Certificate = New-SelfSignedCertificate #certParameters ;
$certificateLocation = $CertStoreLocation + "\" + $global:CertificateInfo.Certificate.Thumbprint ;
Export-PfxCertificate -Cert $certificateLocation -FilePath "$($CertificatePath)" -Password $certificatePassword
}
This is how I invoke the code above:
Connect-Azure -TenantId "your tenant ID here"
Select-Certificate -ThumbPrint "your thumbprint here"
Add-AzureADApplicationKeyCredential -DisplayName "your-displayname-here"
Shown Below are entries in my application manifest the 1st I added manually and the 2nd I added using New-AzureADApplicationKeyCredential cmdlet. They are the same certificate
{
"customKeyIdentifier": "7IzWH13za4loQI6RvMtQ4uewh1g=",
"endDate": "2019-12-15T16:49:37Z",
"keyId": "fd7be8fc-e44f-4d46-a0e4-fc4ef71b0833",
"startDate": "2017-12-18T19:12:15Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": null
},
{
"customKeyIdentifier": "N0l6V0gxM3phNGxvUUk2UnZNdFE0dWV3aDFnPQ==",
"endDate": "2019-12-18T19:22:10Z",
"keyId": "04b0e6a9-bac5-4d3f-be5e-57ddc2976886",
"startDate": "2017-12-19T15:47:15.9136239Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": null
},
Finally a screen shot from the Keys menu in the app registration
As you can see the only way to preserve the thumbprint seems to be to NOT use the New-AzureADApplicationKeyCredential cmdlet
I found the answer. I used ILSPY to examine the source code and the cmdlet takes the string and converts it into a byte[] using
keyCredential.CustomKeyIdentifier = Encoding.ASCII.GetBytes(this.CustomKeyIdentifier);
and while the resulting certificate works the keyCertificateIdentifier is obviously encoded and displayed incorrectly. BTW I did 3 days of searching and used code from various places on the web and everyone I copied from still had it wrong.
Simple solution was to call cmdlet Set-AzureADApplication rather than cmdlet New-AzureADApplicationKeyCredential. This requires me to create a Microsoft.Open.AzureAD.Model.KeyCredential in powershell. Feel free to use the code below
$global:CertificateInfo = #{} ;
function Connect-Azure {
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[string] $TenantId
)
Write-Host "Connect-Azure - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters"
Write-Host " TenantId - $($TenantId)"
$ErrorActionPreference = 'Stop';
Connect-AzureAD -TenantId $TenantId
Write-Host "Connect-Azure - Exit - $($MyInvocation.MyCommand.Name)"
}
function Add-AzureADApplicationKeyCredential {
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[string] $DisplayName,
[parameter(Mandatory=$false)]
[Switch] $Force
)
Write-Host "Add-AzureADApplicationKeyCredential - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Add-AzureADApplicationKeyCredential - Parameters"
Write-Host " DisplayName - $($DisplayName)"
$ErrorActionPreference = 'Stop';
if ($global:CertificateInfo.Certificate -eq $null)
{
throw "No certificate has been selected or created yet."
}
$filter = "DisplayName eq '" + $($DisplayName) + "'" ;
$global:CertificateInfo.Application = Get-AzureADApplication -filter $filter
$certificateThumbprint = [System.Convert]::ToBase64String($global:CertificateInfo.Certificate.GetCertHash()) ;
foreach($keyCredential in $global:CertificateInfo.Application.KeyCredentials)
{
[String]$keyCredentialThumbPrint = [System.Convert]::ToBase64String($keyCredential.CustomkeyIdentifier) ;
if([String]::Equals($keyCredentialThumbPrint,$certificateThumbprint,[StringComparison]::CurrentCultureIgnoreCase)) {
throw "This certificate already exists within the keyCredentials collection with KeyId" + "'" + $keyCredential.KeyId + "'" ;
}
}
$keycredential = New-Object Microsoft.Open.AzureAD.Model.KeyCredential
$keycredential.CustomKeyIdentifier = $global:CertificateInfo.Certificate.GetCertHash() ;
$keycredential.Value = $global:CertificateInfo.Certificate.GetRawCertData() ;
$keycredential.EndDate = $global:CertificateInfo.Certificate.NotAfter ;
$keycredential.StartDate = $global:CertificateInfo.Certificate.NotBefore ;
$keycredential.Type = "AsymmetricX509Cert"
$keycredential.Usage = "Verify" ;
$keycredential.KeyId = [Guid]::NewGuid().ToString() ;
$global:CertificateInfo.Application.KeyCredentials.Add($keycredential) ;
Set-AzureADApplication -ObjectID $global:CertificateInfo.Application.ObjectId -KeyCredentials $global:CertificateInfo.Application.KeyCredentials
Write-Host "Add-AzureADApplicationKeyCredential - Exit"
}
function Select-Certificate {
[CmdletBinding()]
param
(
[parameter(Mandatory=$false)]
[string] $CertStoreLocation = "Cert:\LocalMachine\My",
[parameter(Mandatory=$true)]
[string] $ThumbPrint
)
Write-Host "Create-SelfSignedCertificate - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters" $ErrorActionPreference = 'Stop';
$certificateLocation = $CertStoreLocation + "\" + $ThumbPrint ;
$global:CertificateInfo.Certificate = (Get-ChildItem –Path "$($certificateLocation)")
}
function Create-SelfSignedCertificate {
[CmdletBinding()]
param
(
[parameter(Mandatory=$false)]
[string] $Subject,
[parameter(Mandatory=$false)]
[string] $HashAlgorithm = "SHA256",
[parameter(Mandatory=$false)]
[string] $CertStoreLocation = "Cert:\LocalMachine\My",
[parameter(Mandatory=$true)]
$NotAfter
)
## see https://blogs.technet.microsoft.com/scotts-it-blog/2014/12/30/working-with-certificates-in-powershell/
Write-Host "Create-SelfSignedCertificate - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters"
if([string]::IsNullOrEmpty($Subject)) {
$currentDate = (Get-Date) ;
$Subject = [String]::Format("SelfSigned{0:yyyymmddHHMMss}",$currentDate) ;
}
Write-Host " Subject - $($Subject)"
Write-Host " HashAlgorithm - $($HashAlgorithm)"
Write-Host " CertStoreLocation - $($CertStoreLocation)"
Write-Host " NotAfter - $($NotAfter)"
$ErrorActionPreference = 'Stop';
Write-Host "Create-SelfSignedCertificate - Exit - $($MyInvocation.MyCommand.Name)"
$SaveChooser = New-Object -Typename System.Windows.Forms.SaveFileDialog
$SaveChooser.CreatePrompt = $false ;
$SaveChooser.Title = "Save certficate" ;
$SaveChooser.DefaultExt = "pfx" ;
$dialogResult = $SaveChooser.ShowDialog()
if($dialogResult -eq [System.Windows.Forms.DialogResult]::Cancel) {
return ;
}
$CertificatePath = $SaveChooser.Filename ;
$certificatePassword = Read-host "Please provide a password for the exported certificate." -AsSecureString
$certParameters = #{} ;
$certParameters.CertStoreLocation = $CertStoreLocation;
$certParameters.Subject = $Subject;
$certParameters.KeySpec = "KeyExchange";
$certParameters.HashAlgorithm = $HashAlgorithm;
$certParameters.CertStoreLocation = $CertStoreLocation;
if ($NotAfter -ne $null) {
$certParameters.NotAfter = $NotAfter;
}
$global:CertificateInfo.Certificate = New-SelfSignedCertificate #certParameters ;
$certificateLocation = $CertStoreLocation + "\" + $global:CertificateInfo.Certificate.Thumbprint ;
Export-PfxCertificate -Cert $certificateLocation -FilePath "$($CertificatePath)" -Password $certificatePassword
}
this results in a manifest that looks like
"keyCredentials": [
{
"customKeyIdentifier": "KjS6U6xucxo5kuI1YAwykzrmBKE=",
"endDate": "2019-12-19T19:34:29Z",
"keyId": "de9bd300-ecdc-43d0-a5a6-e946cce10019",
"startDate": "2017-12-19T19:24:50Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": null
}
],
and the display of the keys in the Azure portal looks like this
the Base64 string in the manifest 'KjS6U6xucxo5kuI1YAwykzrmBKE=' now shows up correctly as the hex representation of the certificate thumbprint '2A34BA53AC6E731A3992E235600C32933AE604A1'.
So in closing:
The duplicate check works correctly.
The Azure portal correctly shows the thumbprint of the certificate being used.
The process is automated to reduce the possibility of cut/paste errors.
Does anyone know how Azure is modifying the customKeyIdentifier so
that I can get my duplicate check to work?
First, you're right. Azure allows you upload one certificates for many times. But each uploading action will get one unique KeyId for the certificate.
I understand what you want to achieve. But My scripts is for find whether the certificate is already uploaded. If you want to duplicate check on the uploaded certificates, I think it be better go to Azure portal and find the same certificate quickly, rather than using Powershell. Here is my scripts:
$certs = Get-AzureADApplicationKeyCredential -ObjectId 25f83866-561f-4cf2-b7a6-d623d55864df
$base64Thumbprint = [System.Convert]::ToBase64String($cer.GetCertHash()) # $cer is your local certificate
Foreach ($certificate in $certs)
{
$customkeyIdentifier = $certificate.CustomKeyIdentifier
$UploadedThumbprint = [System.Convert]::ToBase64String($customkeyidentifier)
If($UploadedThumbprint -eq $base64Thumbprint)
{
Write-Host "This certificate is same as yours and its KeyId is" : $certificate.keyId -ForegroundColor Red
}
else
{
Write-Host "This certificate is different from your cert and its KeyId is" : $certificate.keyId -ForegroundColor Cyan
}
}
Here is my result:
Hope this helps!
I am trying to get the values of the properties of an Active Directory instance.
But it keeps giving me null exceptions
The code I am using is as follows.
var xs = PowerShell.Create()
.AddScript("Get-ADComputer -Identity COM-PC-003$ -Properties * | select operatingsystem, accountexpires")
.AddCommand("out-string");
Collection<PSObject> results = xs.Invoke();
//Console.WriteLine(xs);
foreach (var str in results)
{
Console.WriteLine(str.Members["operatingsystem"].Value.ToString());
Console.ReadLine();
//System.Diagnostics.Debug.WriteLine(str.Properties["operatingsystem"].Value);
}
How can I fix this problem?
You can try to do this:
while (true) {
Console.WriteLine("Enter Hostname");
var hn = Console.ReadLine();
var xs = PowerShell.Create().AddScript(
"$comp = Get-ADComputer -Identity " + hn +
" -Properties *" + Environment.NewLine +
"$obj = New-Object -TypeName psobject" +
" -Property #{Host=$comp.operatingsystem;accountexpires = $comp.accountexpires}" +
Environment.NewLine +
"$obj1 = $obj | select -ExpandProperty Host ; $obj2 = $obj | select -ExpandProperty accountexpires ; $out = $obj1 + ' ; ' + $obj2 ; $out").AddCommand("out-string");
Collection<PSObject> results = xs.Invoke();
//Console.WriteLine(xs);
foreach (var str in results)
{
Console.WriteLine("You want to see only OS vers? If its true - enter H, also enter E for see accountexpires or A for see all info");
ConsoleKeyInfo c = Console.ReadKey();
if (c.KeyChar == 'H')
{
Console.WriteLine(str.ToString().Split(';')[0]);
Console.ReadLine();
}
if (c.KeyChar == 'E')
{
Console.WriteLine(str.ToString().Split(';')[1]);
Console.ReadLine();
}
if (c.KeyChar == 'A')
{
Console.WriteLine(str.ToString());
Console.ReadLine();
}
}
}
When button1 is clicked, the below code is executed which will run a PowerShell script to get the current SQL Server Instances. However when this is run, the result set (results variable) has a count of 0 rows from the PowerShell output. When I run the same code in native PowerShell it displays 3 rows with the instance names.
Can anyone advise if I am missing something?
private void button1_Click(object sender, EventArgs e)
{
//If the logPath exists, delete the file
string logPath = "Output.Log";
if (File.Exists(logPath))
{
File.Delete(logPath);
}
string[] Servers = richTextBox1.Text.Split('\n');
//Pass each server name from the listview to the 'Server' variable
foreach (string Server in Servers)
{
//PowerShell Script
string PSScript = #"
param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string] $server)
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force;
Import-Module SQLServer;
Try
{
Set-Location SQLServer:\\SQL\\$server -ErrorAction Stop;
Get-ChildItem | Select-Object -ExpandProperty Name;
}
Catch
{
echo 'No SQL Server Instances';
}
";
//Create PowerShell Instance
PowerShell psInstance = PowerShell.Create();
//Add PowerShell Script
psInstance.AddScript(PSScript);
//Pass the Server variable in to the $server parameter within the PS script
psInstance.AddParameter("server", Server);
//Execute Script
Collection<PSObject> results = new Collection<PSObject>();
try
{
results = psInstance.Invoke();
}
catch (Exception ex)
{
results.Add(new PSObject((Object)ex.Message));
}
//Loop through each of the results in the PowerShell window
foreach (PSObject result in results)
{
File.AppendAllText(logPath, result + Environment.NewLine);
// listBox1.Items.Add(result);
}
psInstance.Dispose();
}
}
To get an possible PowerShell error I would try sth. like this:
private void button1_Click(object sender, EventArgs e)
{
//If the logPath exists, delete the file
string logPath = "Output.Log";
if (File.Exists(logPath)) {
File.Delete(logPath);
}
string[] Servers = richTextBox1.Text.Split('\n');
//Pass each server name from the listview to the 'Server' variable
foreach (string Server in Servers) {
//PowerShell Script
string PSScript = #"
param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string] $server)
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force;
Import-Module SQLServer;
Try
{
Set-Location SQLServer:\\SQL\\$server -ErrorAction Stop;
Get-ChildItem | Select-Object -ExpandProperty Name;
}
Catch
{
echo 'No SQL Server Instances';
}
";
using (PowerShell psInstance = PowerShell.Create()) {
psInstance.AddScript(PSScript);
psInstance.AddParameter("server", Server);
Collection<PSObject> results = psInstance.Invoke();
if (psInstance.Streams.Error.Count > 0) {
foreach (var errorRecord in psInstance.Streams.Error) {
MessageBox.Show(errorRecord.ToString());
}
}
foreach (PSObject result in results) {
File.AppendAllText(logPath, result + Environment.NewLine);
// listBox1.Items.Add(result);
}
}
}
}
The reason it isn't working is that psInstance.AddParameter only adds parameters to commands, it doesn't work with a script. You'll need to find another way of getting the $server parameter into the script. Try these two powershell examples to see what I mean. The first will output all processes (ignores the AddParameter) while the second only shows svchost processes.
1)
$ps = [system.management.automation.powershell]::create()
$ps.AddScript("get-process")
$ps.AddParameter("name","svchost")
$ps.invoke()
2)
$ps = [system.management.automation.powershell]::create()
$ps.AddCommand("get-process")
$ps.AddParameter("name","svchost")
$ps.invoke()
I managed to get round this issue by using the Win32_service instead of SQLPS.
Param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string] $server)
$localInstances = #()
[array]$captions = GWMI Win32_Service -ComputerName $server | ?{$_.Name -match 'mssql *' -and $_.PathName -match 'sqlservr.exe'} | %{$_.Caption}
ForEach($caption in $captions)
{
if ($caption -eq 'MSSQLSERVER')
{
$localInstances += 'MSSQLSERVER'
}
else
{
$temp = $caption | %{$_.split(' ')[-1]} | %{$_.trimStart('(')} | %{$_.trimEnd(')')}
$localInstances += ""$server\$temp""
}
}
$localInstances;
function LogMe() {
Param(
[parameter(Mandatory = $true, ValueFromPipeline = $true)]$logEntry,
[switch]$display,
[switch]$error,
[switch]$warning,
[switch]$progress
)
if ($error) {
$logEntry = "[ERROR] $logEntry"
Write-Host "$logEntry" -ForegroundColor Red
} elseif ($warning) {
Write-Warning "$logEntry"
$logEntry = "[WARNING] $logEntry"
} elseif ($progress) {
Write-Host "$logEntry" -ForegroundColor Green
} elseif ($display) {
Write-Host "$logEntry"
}
#$logEntry = ((Get-Date -uformat "%D %T") + " - " + $logEntry)
$logEntry | -force Out-File $logFile -Append
}
The above code spits out an error described in the title. I tried -force any other suggestions?
It's not C# per se but the error I'm getting is coming from C# when I run using pipeline.invoke.