我正在尝试检查 Powerhell 脚本是否以管理员身份运行。在网上搜索后,我得到了一些运行良好的示例代码。
为了获取该WindowsPrincipal对象,我找到了两个示例代码,如下所示。
第一的:
New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
Run Code Online (Sandbox Code Playgroud)
第二:
[Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
Run Code Online (Sandbox Code Playgroud)
第二个让我很困惑。
根据此页面,我知道这[ ]是一个强制转换运算符。根据此页面,PowerShell 是基于 .NET Framework 构建的。在我看来,这意味着上述两个PowerShell脚本可以转换为C#。
所以我尝试一下。
当我将第一个 PowerShell 脚本转换为 C# 时。它工作正常,如下所示。
## First PowerShell script
New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
// C#
var wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
Run Code Online (Sandbox Code Playgroud)
但是当我尝试将第二个 PowerShell 脚本转换为 C# 时。我收到编译错误。IDE 告诉我WindowsIdentity不能转换为WindowsPrincipal.
## Second PowerShell script
[Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
// both C# code below cause compile error
var wp = System.Security.Principal.WindowsIdentity.GetCurrent() as System.Security.Principal.WindowsPrincipal;
var wp2 = (System.Security.Principal.WindowsPrincipal)System.Security.Principal.WindowsIdentity.GetCurrent();
Run Code Online (Sandbox Code Playgroud)
正如我在C#上尝试的那样,System.Security.Principal.WindowsIdentity类型不能直接转换为System.Security.Principal.WindowsPrincipal类型。但为什么第二个 PowerShell 脚本可用呢?
或者[ ]第二个PowerShell脚本中的运算符不是类型转换运算符?
也许这个运算符不仅仅是转换对象类型?
第一个 PowerShell 脚本和第二个 PowerShell 脚本有什么区别?
我还遗漏了其他东西吗?
TLDR:PowerShell 可以做Magic。C# 无法实现 Magic。
PowerShell 可以同时处理链锯、保龄球瓶和球。
C# 只能在提前定义的情况下才能玩弄球。尝试在杂耍例程中添加新的电锯会导致杂耍者(编译器)抱怨。
问题在于函数、对象类型之间的差异以及如何转换对象类型。
System.Security.Principal是基础 .NET 库。该库可由 C# 和 PowerShell 使用。
WindowsIdentity.GetCurrent()是库中的一个函数。
WindowsPrincipal是一个对象类型,例如stringor int。
调用WindowsIdentity.GetCurrent()会返回一个WindowsIdentity对象,然后您可以在代码中使用该对象。
由于WindowsIdentity不一定是您想要使用的对象类型,因此我们希望使用对象WindowsPrincipal。不幸的是我们不能直接将 from 转换WindowsIdentity为WindowsPrincipalobject。我们必须使用WindowsPrincipal构造函数。
New-Object在 PowerShell 中,您可以通过cmdlet 或首次使用变量来创建新对象。这种便利是因为 PowerShell 是一种脚本语言,其中使用变量(例如)$a = 1隐式创建新变量。例如
PS C:\> Get-Variable test
Get-Variable : Cannot find a variable with the name 'test'.
At line:1 char:1
+ Get-Variable test
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (test:String) [Get-Variable], ItemNotFoundException
+ FullyQualifiedErrorId : VariableNotFound,Microsoft.PowerShell.Commands.GetVariableCommand
PS C:\> $test = 1
PS C:\> Get-Variable test
Name Value
---- -----
test 1
Run Code Online (Sandbox Code Playgroud)
使用New-Object示例:
New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
Run Code Online (Sandbox Code Playgroud)
这是正确的做法。您正在创建一个类型为 的新对象WindowsPrincipal,并将 Windows 标识传递给构造函数。
第二种方法:
[Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
Run Code Online (Sandbox Code Playgroud)
是“错误的”,因为它使用了强制转换,之前我们说过我们不能直接从WindowsIdentity对象强制转换WindowsPrincipal。那么这是如何运作的呢?嗯,我之前说过 PowerShell 具有 Magic 功能,我稍后会讲到这一点。首先让我们看看正确的C#代码:
在 C# 中调用 .NET Framework 特定函数在语法上与 PowerShell 不同。您收到的特定编译错误的原因是因为我们正在尝试转换对象,但我们不能。
这个例子:
using System.Security.Principal;
var wp = WindowsIdentity.GetCurrent() as WindowsPrincipal; // compile error
Run Code Online (Sandbox Code Playgroud)
编译器将其翻译为:
WindowsIdentity.GetCurrent()
Run Code Online (Sandbox Code Playgroud)
运行功能GetCurrent()
as WindowsPrincipal;
Run Code Online (Sandbox Code Playgroud)
预期返回类型为WindowsPrincipal<-- 编译时错误。编译错误是因为该函数没有返回类型WindowsPrincipal,而是返回类型WindowsIdentity。
第二个示例也是一个不起作用的变体,因为它无法直接投射对象。例如
using System.Security.Principal;
var wp = (WindowsPrincipal) WindowsIdentity.GetCurrent(); // compile error
Run Code Online (Sandbox Code Playgroud)
编译器将其翻译为:
WindowsIdentity.GetCurrent()
Run Code Online (Sandbox Code Playgroud)
运行函数GetCurrent()并返回对象WindowsIdentity。
(WindowsPrincipal) WindowsIdentity.GetCurrent();
Run Code Online (Sandbox Code Playgroud)
获取WindowsIdentity对象并直接将其转换为WindowsPrincipal类型,但它不能。
正确的C#代码还需要new关键字是:
var wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
Run Code Online (Sandbox Code Playgroud)
编译器将其翻译为:
WindowsIdentity.GetCurrent()
Run Code Online (Sandbox Code Playgroud)
运行函数GetCurrent()并返回对象WindowsIdentity。
new WindowsPrincipal(WindowsIdentity.GetCurrent())
Run Code Online (Sandbox Code Playgroud)
创建一个新WindowsPrincipal对象,并将该WindowsIdentity对象传递给构造函数。现在有效。
那么为什么第二个例子是这样的:
[Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
Run Code Online (Sandbox Code Playgroud)
在 PowerShell 中工作时做了一些“错误”的事情?因为 PowerShell 是一种脚本语言,并且是动态解释的,并且可以使用Magic,所以它可以解释上面的内容并执行一些类型转换 Magic Quote:
基本上,每当您在 PowerShell 中进行类型转换时,它都会执行 Magic 并尝试每种方法来为您动态动态转换类型。这就是为什么它可以处理你向杂耍者扔新电锯或保龄球瓶的原因。PowerShell 可以解释为我们并不是试图将电锯转换成球,而是电锯只是另一个物体,而且我们已经知道如何处理物体。
这种解释不是 .NET 的一部分,因此 C# 无法做到这一点,我们必须显式定义所有内容,并正确执行所有操作。这意味着您可以将所有 C# 和 .NET 代码转换为有效的 PowerShell 代码,但反之则不然。