How to execute multi-line powershell command - c#

Trying to execute a PowerShell command in asp.net c# but it returns no results, where am I going wrong?
var shell = PowerShell.Create();
var script = $#"$Groups = Get-ADGroup {groupname}; $members = ForEach ($Group in $Groups) {{Get-AdGroupMember -Identity $Group -Recursive}} ; $members | Get-AdUser -Properties Department | Select-Object Name, Department | Sort Department, Name";
shell.Commands.AddScript(script);
var results = shell.Invoke();
foreach (var psObject in results)
{
dt.Rows.Add(new object[] { psObject.Members["Name"].Value, psObject.Members["Department"].Value });
}
Gridview2.DataSource = dt;
Gridview2.DataBind();
It executes perfectly in PowerShell. Separating the command over lines as per suggested answer does not work.
Edit - I took another look at my powershell and realised that it was unecessarily complicated. I changed it to the below and it now works. Still does not explain why something that returns results in powershell does not work when ran from asp.net.
Get-AdGroupMember -Identity {groupname} -Recursive | Get-AdUser -Properties Department | Select-Object Name, Department | Sort Department, Name

Related

How to read numeric string as string in sqlite table

I am using System.Data.SQLite.Core nuget package in my asp.net core 3 app.
I have a SQLite DB with my table, assuming something like this:
+-----+------------+-----+
| ... | Phone | ... |
+-----+------------+-----+
| --- | 0123456789 | --- |
+-----+------------+-----+
| --- | 9876543210 | --- |
+-----+------------+-----+
I do a simple query
command = new SQLiteCommand("SELECT * FROM Table", connection);
var reader = await command.ExecuteReaderAsync();
and get data in my reader.
But when I try to Istance the values in an object I can read and cast every value to its type, however I can't cast the phone value into a string (I have declared it as a string in my DB), I mean I can cast it using explicit cast
var p = reader[index2];
var t = p.GetType().Name; //--> String
var myobj = new MyObj(othervalues: reader.GetString(index1), phone: (string)reader[index2]);
That is working but why can't I simply do this ?
... phone: reader.GetString(index2)...
And there is a way to do it ?
Thanks for your answer!
Update:
So apparently change colum definition from STRING to TEXT seems to work using reader.GetString(index) and allows to store phone number like '0000000001' too, without deleting zeros.

how to identify query statement has a subquery in it?

Developing an C# project for SQL Training and giving different exercises based on training on each topic. One of the exercise is to write a query using Sub-Query. which needs to be evaluated whether the user has used/implemented Sub query in the Query Statment.
Q: Write a sql query to show the SalesOrderID,LineTotal,average LineTotal from the Sales.SalesOrderDetail table using Sub query
Select SalesOrderID,LineTotal [LineTotal],
(Select AVG(LineTotal) from Sales.SalesOrderDetail) as [AverageLineTotal]
from Sales.SalesOrderDetail
[AverageLineTotal] is an sub query.
Can we identify it by any means?? like execution plan Or SP to identify it has an sub query in the statement
Is there any way to identify it through execution Plans??
If this is a c# project you can parse the query with regex to find if the query contains (select {any other text}).
public static void Main()
{
var sql = #"Select SalesOrderID,LineTotal [LineTotal],(Select AVG(LineTotal) from Sales.SalesOrderDetail) as [AverageLineTotal] from Sales.SalesOrderDetail";
Console.WriteLine(DoesSqlContainSubquery(sql));
}
public bool DoesSqlContainSubquery(string sql)
{
var regexTest = new Regex(#"\( *Select .*\)", RegexOptions.IgnoreCase);
var containsSubquery = regexTest.IsMatch(sql);
return containsSubquery;
}
Parsing ad-hoc scripts is inherently complex due to the plethora T-SQL constructs and options. That being said, a robust method for targeted use cases is parsing scripts with the Microsoft.SqlServer.TransactSql.ScriptDom.
Below is an example PowerShell script that uses the script DOM assembly from the official Microsoft Dacfx NuGet package, downloading and extracting it if needed.
# Add TSqlScript DOM assembly reference, downloading and extracting to the specified location if needed
$scriptDomAssemblyPath = "C:\Temp\Microsoft.SqlServer.TransactSql.ScriptDom.dll"
$scriptDomNuGetUrl = "https://www.nuget.org/api/v2/package/Microsoft.SqlServer.DacFx.x64/150.4384.2"
if(![System.IO.File]::Exists($scriptDomAssemblyPath)) {
$response = Invoke-WebRequest -Uri $scriptDomNuGetUrl
if ($response.StatusCode -ne 200) {
throw "Unable to download Microsoft.SqlServer.TransactSql.ScriptDom NuGet package: $response.StatusCode : $response.StatusDescription"
}
$tempZipFilePath = "$([System.IO.Path]::GetTempPath())/$([System.IO.Path]::GetRandomFileName()).zip"
[System.IO.File]::WriteAllBytes($tempZipFilePath, $response.Content)
$response.BaseResponse.Dispose()
$tempUnzipFolderPath = "$([System.IO.Path]::GetTempPath())/$([System.IO.Path]::GetRandomFileName())"
Expand-Archive -Path $tempZipFilePath -DestinationPath $tempUnzipFolderPath
$tempZipFilePath | Remove-Item
Move-Item "$tempUnzipFolderPath\lib\net46\Microsoft.SqlServer.TransactSql.ScriptDom.dll" "$scriptDomAssemblyPath"
$tempUnzipFolderPath | Remove-Item -Recurse
}
Add-Type -Path $scriptDomAssemblyPath
# script to be parsed
$scriptText = #"
Select SalesOrderID,LineTotal [LineTotal],
(Select AVG(LineTotal) from Sales.SalesOrderDetail) as [AverageLineTotal]
from Sales.SalesOrderDetail
"#
#parse script
$parser = New-Object Microsoft.SqlServer.TransactSql.ScriptDom.TSql150Parser($true)
$parseErrors = New-Object System.Collections.Generic.List[Microsoft.SqlServer.TransactSql.ScriptDom.ParseError]
$scriptReader = New-Object System.IO.StringReader($scriptText)
$script = $parser.Parse($scriptReader, [ref]$parseErrors)
if($parseErrors.Count -gt 0) {
throw "$($parseErrors.Count) parsing errors"
}
# sanity check for expected SELECT query
if(($script.Batches.Count -ne 1) -or ($script.Batches[0].Statements.Count -ne 1) -or ($script.Batches[0].Statements[0].QueryExpression -eq $null)) {
throw "script with single SELECT statement expected"
}
# find scalar subquery expression in select list
$subQueryFound = $false
foreach($selectElement in $script.Batches[0].Statements[0].QueryExpression.SelectElements) {
if($selectElement.Expression.ToString() -eq "Microsoft.SqlServer.TransactSql.ScriptDom.ScalarSubquery") {
$subQueryFound = $true
break
}
}
# show if subquery was used
if($subQueryFound) {
Write-Host "A subquery is used"
}
else {
Write-Host "A subquery is not used"
}

Export DataTable to Excel using PowerShell

I have a function to create System.Data.Datatables from a simple input of TableName and ColumnName-Array. After filling the tables I want to add them to a dataset and export this one into an excel document.
The code below does that, however in the export to excel there is one bit that I find a bit unelegant. Every table will have to be exported into a csv and then reimported to excel.
Is there a better cleaner way to use DataTables directly in Excel?
Function MakeTable ($TableName, $ColumnArray)
{
$btab = New-Object System.Data.DataTable("$TableName")
foreach($Col in $ColumnArray)
{
$MCol = New-Object System.Data.DataColumn $Col;
$btab.Columns.Add($MCol)
}
return , $btab
}
function DataSetToExcel ($Ds, $workdirectory)
{
$excel = New-Object -ComObject excel.application
$workbook = $excel.Workbooks.Add(1)
$i = 0
for($DsIndex=0;$DsIndex -lt $ds.Tables.Count;$DsIndex++)
{
$Table = $ds.tables[$Dsindex]
if($Dsindex -ne 0)
{
$workbook.worksheets.Add() | Out-Null #Erstellt neues Arbeitsblatt
}
$Table | Export-Csv "$workdirectory\input.csv" -Encoding UTF8 -NoTypeInformation -Force -Delimiter ";"
$inputCSV = "C:\Temp\Test\input.csv"
$worksheet = $workbook.worksheets.Item(1)
$worksheet.Name = $Table.TableName
$TxtConnector = ("TEXT;" + $inputCSV)
$Connector = $worksheet.QueryTables.add($TxtConnector,$worksheet.Range("A1"))
$query = $worksheet.QueryTables.item($Connector.name)
$query.TextFileOtherDelimiter = $Excel.Application.International(5)
$query.TextFileParseType = 1
$query.AdjustColumnWidth = 1
$query.Refresh() | Out-Null
$query.Delete()
}
$outputXLSX = "$workdirectory\output.xlsx"
$Workbook.SaveAs($outputXLSX,51)
$excel.Quit()
}
function MakeTestTable ($TableName)
{
$TestTable = MakeTable $TableName #("A","B")
for($i=0;$i -lt 10; $i++)
{
$aRow = $TestTable.NewRow()
$aRow["A"] = (10-$i).ToString()
$aRow["B"] = $i.ToString()
$TestTable.Rows.Add($aRow)
}
return , $TestTable
}
$db = New-Object System.Data.DataSet
for($cx=0;$cx -lt 10;$cx++)
{
$tab1 = MakeTestTable "$cx"
$db.Tables.Add($tab1)
}
DataSetToExcel $db "C:\Temp\Test"
Check out my PowerShell Excel Module on Github. You can also grab it from the PowerShell Gallery.
It also works directly with CSV format using Import-Csv or ConvertFrom-Csv (basically any PowerShell object array).
function New-Person {
param($First,$Last)
$row=$dataTable.NewRow()
$row["First"]=$First
$row["Last"]=$Last
$dataTable.Rows.Add($row)
}
$dataTable = New-Object System.Data.DataTable("Test")
$dataTable.Columns.Add((New-Object System.Data.DataColumn "First"))
$dataTable.Columns.Add((New-Object System.Data.DataColumn "Last"))
New-Person John Doe
New-Person Tom Doe
New-Person Jane Doe
New-Person Mary Doe
$dataTable |
Select First, Last |
Export-Excel c:\temp\people.xlsx -AutoSize -Show
Since you tagged this with C#, If you have excel on the computer this will be run on, you can use the interop library. I used it for a project I did, using code I found in this SO question.

How to get a driver list in Windows?

What is the best way to create a list of all locally installed drivers with C# and the .net Framework?
It should work for Vista based Windows versions.
The list should contain:
Name of the driver
Version of the driver
Location of the driver on the HDD.
Any suggestions / help is appreciated.
Till now I have found a wmi query: that points to the right direction.
Win32_PnPSignedDriver class
("Select * from Win32_PnPSignedDriver")
This should get you started:
SelectQuery query = new System.Management.SelectQuery(
"select name, pathname from Win32_Service");
using (ManagementObjectSearcher searcher =
new System.Management.ManagementObjectSearcher(query))
{
foreach (ManagementObject service in searcher.Get())
{
Console.WriteLine(string.Format(
"Name: {0}\tPath : {1}", service["Name"], service["pathname"]));
}
}
To get a list of drivers use the powershell script:
Get-WmiObject -Class "Win32_PnPSignedDriver" | Select Caption, Description, DeviceID, DeviceClass, DriverVersion, DriverDate, DriverProviderName, InfName
To get a list of driver paths use the powershell script:
Get-WmiObject -Class "Win32_PnPSignedDriverCIMDataFile" | Select Dependent| foreach {
$y = $_ -match '(?<=")(.*?)(?=")'
$Matches[0]
}
At the moment i am just not sure if there are other drivers that this query doesn't match.
To use Powershell in C# use: System.Management.Automation

how to run the powershell script with 2 foreach in c#

This is the powershell script I want to run in c# :
ForEach ($Mailbox in Get-Mailbox) {Get-ActiveSyncDeviceStatistics -Mailbox
$Mailbox.Identity –ErrorAction SilentlyContinue |
SelectDeviceFriendlyName,Devicetype,DeviceUserAgent | ForEach-Object { $_ | Add-Member –
MemberType NoteProperty -Name "MailboxIdentity" -value $Mailbox}}
I could complete the c# coding upto first foreach loop in powershell script, but I do not know how implement the 2nd foreach that uses $mailbox variable along with the coding given below.
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("Get-Mailbox");
command.AddCommand("where-object");
command.AddParameter("Filterscript", ScriptBlock.Create("!$_.name.startswith \"DiscoverySearchMailbox\")"));
powershell.Commands = command;
powershell.Runspace = CreateRunSpace.GetRunSpace();
var result = powershell.Invoke();
 
PSCommand command1 = new PSCommand();
command1.AddCommand("write-output");
command1.AddParameter("InputObject", result);
command1.AddCommand("Foreach-Object");
command1.AddParameter("Process", ScriptBlock.Create("Get-ActiveSyncDeviceStatistics -Mailbox $_.Identity"));
powershell.Commands = command1;
powershell.Runspace =
CreateRunSpace.GetRunSpace();
var result1 = powershell.Invoke();
I'm stuck at 2nd foreach loop to add-member while adding the output of get-mailbox.
Appreciate your help and suggestions in advance. Thank you.

Categories