目录
Windows系统共享文件夹或打印机等设备的dos脚本自动化
2.1、激活Windows的Administrator账户;
2.2、设置Windows的Administrator账户的密码;
2.3、重启Windows,并以Administrator账户登录(Logon);
2.4、验证本机或远程计算机的管理组账号的Logon,登入该计算机
2.5、共享对象的完整性访问控制列表ICACLS的“安全”授权
三、App中嵌入上述脚本运行(Delphi调用Windows Dos内部外部命令的脚本或PowerShell脚本的通行做法)
3.2、调ShellExecute或ShellExecuteEx的Windows API函数执行上述脚本;
3.2.3、Tray notification definitions托盘通知定义:
Windows系统共享文件夹或打印机等设备的dos脚本自动化
一、概述
很多时候,我们需要通过App来共享本机或远程计算机的文件夹或打印机等设备。怎么做呢?
步骤:
1.1、激活Windows的Administrator账户;
1.2、设置Windows的Administrator账户的密码;
1.3、重启Windows,并以Administrator账户登录(Logon);
1.4、验证本机或远程计算机的管理组账号的Logon,登入该计算机;
1.5、共享对象的完整性访问控制列表的“安全”授权;
1.6、共享对象的访问控制列表的“高级共享”授权;
1.7、需共享的文件夹或打印机等设备的“共享”授权。
执行的结果:
就是替代了GUI的人机交互,用代码在App中自动化执行,比如就自动化实现了:
网络文件夹(或打印机)共享的结果:
二、脚本实作
步骤:(注意,首次配置,应当在本机执行,而不是在远程操作)
2.1、激活Windows的Administrator账户;
有些操作系统放入初始化安装,Administrator账户名被修改了,计算机账户的"凭据"就变了,所以需要:
NET USER 将创建并修改计算机上的用户帐户。在不进行切换的情况下使用时,将列出
计算机的用户帐户。用户帐户信息存储在用户帐户数据库中。
net user administrator /active:yes
2.2、设置Windows的Administrator账户的密码;
net user Administrator Adm****8
2.1、和2.2、两步可以合二为一:
net user Administrator Adm****8 /active:yes
2.3、重启Windows,并以Administrator账户登录(Logon);
shutdown -i -g -f
2.4、验证本机或远程计算机的管理组账号的Logon,登入该计算机
以正确的密码验证本地或远程计算机的管理员账号,进行Logon登入:
netsh -r 192.168.3.242 -u Administrator -p Adm****8
2.5、共享对象的完整性访问控制列表ICACLS的“安全”授权
icacls F:\我的开发测试文件夹 /grant Everyone:(D,WDAC)
rem 或具体某个登录账户的授权:
rem icacls F:\我的开发测试文件夹 /grant 计算机的某Logon账户:(D,WDAC)
2.6、共享对象的访问控制列表CACLS的“高级共享”授权
cacls F:\我的开发测试文件夹 /T /G Everyone:F
2.7、需共享的文件夹或打印机等设备的“共享”授权
net share MySharedFoderName=F:\我的开发测试文件夹 /GRANT:Everyone,FULL /UNLIMITED
rem MySharedFoderName为共享的友好名
这一步,会遇到与操作系统之间的交互式对话,可以用dos输入输出重定向:
echo off
echo Y | net share MySharedFoderName=F:\我的开发测试文件夹 /GRANT:Everyone,FULL /UNLIMITED
rem或将上述命令输出为批处理文件(MySharingFoder.bat)来执行.
三、App中嵌入上述脚本运行(Delphi调用Windows Dos内部外部命令的脚本或PowerShell脚本的通行做法)
Delphi(或Lazarus类似稍改下即可)的话,步骤就是:
3.1、将你的App进行UAC提权;
unit WinUtils;
{$WARN SYMBOL_PLATFORM OFF}
{$R+}
interface
uses
Windows;
type
TElevatedProc = function(const AParameters: String): Cardinal;
TProcessMessagesMeth = procedure of object;
var
//警告:此功能将在外部进程中执行。
//请勿在此例程中使用任何全局变量!
//仅使用提供的参数:
OnElevateProc: TElevatedProc;
//分配完OnElevateProc后调用此例程:
procedure CheckForElevatedTask;
//以完全管理员权限运行OnElevateProc:
function RunElevated(const AParameters: String; const AWnd: HWND = 0; const AProcessMessages: TProcessMessagesMeth = nil): Cardinal; overload;
//以下4个函数判断并提权:
function IsAdministrator: Boolean;//:当前Logon是管理员吗
function IsAdministratorAccount: Boolean;//:当前Logon是管理员组吗
//UAC(用户账户控制:User Account Control):
function IsUACEnabled: Boolean;//:是否允许UAC的注册表检查
function IsElevated: Boolean;//:提权
//比如,通过某个按钮的句柄来提权:
procedure SetButtonElevated(const AButtonHandle: THandle);
implementation
uses
SysUtils, Registry, ShellAPI, ComObj;
const
RunElevatedTaskSwitch = '0CC5C50CB7D643B68CB900BF000FFFD5'; // some unique value, just a GUID with removed '[', ']', and '-'
function CheckTokenMembership(TokenHandle: THANDLE; SidToCheck: Pointer; var IsMember: BOOL): BOOL; stdcall; external advapi32 name 'CheckTokenMembership';
function RunElevated(const AParameters: String; const AWnd: HWND = 0; const AProcessMessages: TProcessMessagesMeth = nil): Cardinal; overload;
var
SEI: TShellExecuteInfo;
Host: String;
Args: String;
begin
Assert(Assigned(OnElevateProc), 'OnElevateProc must be assigned before calling RunElevated');
if IsElevated then
begin
if Assigned(OnElevateProc) then
Result := OnElevateProc(AParameters)
else
Result := ERROR_PROC_NOT_FOUND;
Exit;
end;
Host := ParamStr(0);
Args := Format('/%s %s', [RunElevatedTaskSwitch, AParameters]);
FillChar(SEI, SizeOf(SEI), 0);
SEI.cbSize := SizeOf(SEI);
SEI.fMask := SEE_MASK_NOCLOSEPROCESS;
{$IFDEF UNICODE}
SEI.fMask := SEI.fMask or SEE_MASK_UNICODE;
{$ENDIF}
SEI.Wnd := AWnd;
SEI.lpVerb := 'runas';
SEI.lpFile := PChar(Host);
SEI.lpParameters := PChar(Args);
SEI.nShow := SW_NORMAL;
if not ShellExecuteEx(@SEI) then
RaiseLastOSError;
try
Result := ERROR_GEN_FAILURE;
if Assigned(AProcessMessages) then
begin
repeat
if not GetExitCodeProcess(SEI.hProcess, Result) then
Result := ERROR_GEN_FAILURE;
AProcessMessages;
until Result <> STILL_ACTIVE;
end
else
begin
if WaitForSingleObject(SEI.hProcess, INFINITE) <> WAIT_OBJECT_0 then
if not GetExitCodeProcess(SEI.hProcess, Result) then
Result := ERROR_GEN_FAILURE;
end;
finally
CloseHandle(SEI.hProcess);
end;
end;
function IsAdministrator: Boolean;
var
psidAdmin: Pointer;
B: BOOL;
const
SECURITY_NT_AUTHORITY: TSidIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
SECURITY_BUILTIN_DOMAIN_RID = $00000020;
DOMAIN_ALIAS_RID_ADMINS = $00000220;
SE_GROUP_USE_FOR_DENY_ONLY = $00000010;
begin
psidAdmin := nil;
try
// Создаём SID группы админов для проверки
//:创建一个SID管理组来检查psidAdmin:
Win32Check(AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
psidAdmin));
// Проверяем, входим ли мы в группу админов (с учётов всех проверок на disabled SID)
//:检查psidAdmin是否属于管理组:
if CheckTokenMembership(0, psidAdmin, B) then
Result := B
else
Result := False;
finally
if psidAdmin <> nil then
FreeSid(psidAdmin);
end;
end;
{$R-}
function IsAdministratorAccount: Boolean;
var
psidAdmin: Pointer;
Token: THandle;
Count: DWORD;
TokenInfo: PTokenGroups;
HaveToken: Boolean;
I: Integer;
const
SECURITY_NT_AUTHORITY: TSidIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
SECURITY_BUILTIN_DOMAIN_RID = $00000020;
DOMAIN_ALIAS_RID_ADMINS = $00000220;
SE_GROUP_USE_FOR_DENY_ONLY = $00000010;
begin
Result := Win32Platform <> VER_PLATFORM_WIN32_NT;
if Result then
Exit;
psidAdmin := nil;
TokenInfo := nil;
HaveToken := False;
try
Token := 0;
HaveToken := OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, Token);
if (not HaveToken) and (GetLastError = ERROR_NO_TOKEN) then
HaveToken := OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token);
if HaveToken then
begin
Win32Check(AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
psidAdmin));
if GetTokenInformation(Token, TokenGroups, nil, 0, Count) or
(GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
RaiseLastOSError;
TokenInfo := PTokenGroups(AllocMem(Count));
Win32Check(GetTokenInformation(Token, TokenGroups, TokenInfo, Count, Count));
for I := 0 to TokenInfo^.GroupCount - 1 do
begin
Result := EqualSid(psidAdmin, TokenInfo^.Groups[I].Sid);
if Result then
Break;
end;
end;
finally
if TokenInfo <> nil then
FreeMem(TokenInfo);
if HaveToken then
CloseHandle(Token);
if psidAdmin <> nil then
FreeSid(psidAdmin);
end;
end;
{$R+}
function IsUACEnabled: Boolean;//UAC(用户账户控制,User Account Control)
var
Reg: TRegistry;
begin
Result := CheckWin32Version(6, 0);//:是Win7及其以后的版本?!
if Result then//:如果是Win7及其以后的版本
begin
Reg := TRegistry.Create(KEY_READ);
try
Reg.RootKey := HKEY_LOCAL_MACHINE;//注册表的这个项:
//HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
if Reg.OpenKey('\Software\Microsoft\Windows\CurrentVersion\Policies\System', False)
then
if Reg.ValueExists('EnableLUA') then
Result := (Reg.ReadInteger('EnableLUA') <> 0)
else
Result := False
else
Result := False;
finally
FreeAndNil(Reg);
end;
end;
end;
function IsElevated: Boolean;
const
TokenElevation = TTokenInformationClass(20);
type
TOKEN_ELEVATION = record
TokenIsElevated: DWORD;
end;
var
TokenHandle: THandle;
ResultLength: Cardinal;
ATokenElevation: TOKEN_ELEVATION;
HaveToken: Boolean;
begin
if CheckWin32Version(6, 0) then
begin
TokenHandle := 0;
HaveToken := OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, TokenHandle);
if (not HaveToken) and (GetLastError = ERROR_NO_TOKEN) then
HaveToken := OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, TokenHandle);
if HaveToken then
begin
try
ResultLength := 0;
if GetTokenInformation(TokenHandle, TokenElevation, @ATokenElevation, SizeOf(ATokenElevation), ResultLength) then
Result := ATokenElevation.TokenIsElevated <> 0
else
Result := False;
finally
CloseHandle(TokenHandle);
end;
end
else
Result := False;
end
else
Result := IsAdministrator;
end;
procedure SetButtonElevated(const AButtonHandle: THandle);
const
BCM_SETSHIELD = $160C;
var
Required: BOOL;
begin
if not CheckWin32Version(6, 0) then
Exit;
if IsElevated then
Exit;
Required := True;
SendMessage(AButtonHandle, BCM_SETSHIELD, 0, LPARAM(Required));
end;
procedure CheckForElevatedTask;
function GetArgsForElevatedTask: String;
function PrepareParam(const ParamNo: Integer): String;
begin
Result := ParamStr(ParamNo);
if Pos(' ', Result) > 0 then
Result := AnsiQuotedStr(Result, '"');
end;
var
X: Integer;
begin
Result := '';
for X := 1 to ParamCount do
begin
if (AnsiUpperCase(ParamStr(X)) = ('/' + RunElevatedTaskSwitch)) or
(AnsiUpperCase(ParamStr(X)) = ('-' + RunElevatedTaskSwitch)) then
Continue;
Result := Result + PrepareParam(X) + ' ';
end;
Result := Trim(Result);
end;
var
ExitCode: Cardinal;
begin
if not FindCmdLineSwitch(RunElevatedTaskSwitch) then
Exit;
ExitCode := ERROR_GEN_FAILURE;
try
if not IsElevated then
ExitCode := ERROR_ACCESS_DENIED
else
if Assigned(OnElevateProc) then
ExitCode := OnElevateProc(GetArgsForElevatedTask)
else
ExitCode := ERROR_PROC_NOT_FOUND;
except
on E: Exception do
begin
if E is EAbort then
ExitCode := ERROR_CANCELLED
else
if E is EOleSysError then
ExitCode := Cardinal(EOleSysError(E).ErrorCode)
else
if E is EOSError then
else
ExitCode := ERROR_GEN_FAILURE;
end;
end;
if ExitCode = STILL_ACTIVE then
ExitCode := ERROR_GEN_FAILURE;
TerminateProcess(GetCurrentProcess, ExitCode);
end;
{ procedure KillProcess;
var
Msg: String;
begin
Msg :=
'IsAdministrator: ' + BoolToStr(IsAdministrator, True) + sLineBreak +
'IsAdministratorAccount: ' + BoolToStr(IsAdministratorAccount, True) + sLineBreak +
'IsUACEnabled: ' + BoolToStr(IsUACEnabled, True) + sLineBreak +
'IsElevated: ' + BoolToStr(IsElevated, True);
MessageBox(0, PChar(Msg), 'Hello from RegisterExtension!', MB_OK or MB_ICONINFORMATION);
KillTask(KillProcessName);
showmessage(KillProcessName);
end; }
end.
3.2、调ShellExecute或ShellExecuteEx的Windows API函数执行上述脚本;
3.2.1、例如:
Lcmd_Cacls_SharingDirName:='echo Y|cacls'+' '
+trim(ADirectoryFullPath)
+' '+'/C'+' '+'/G'+' ' + 'Everyone'+':F';
LSharingCmd_bat:=GPath+'GYtemp' +PathDelim +'Ashare'+LDirName_NotWithDelimiAndPathPrefix +'.bat';
LWinExecResult
:=ShellExecute(
Application.Handle,PChar('open'),
PChar('"'+'c:\windows\system32\cmd.exe'+'"'), //:外部命令的可执行文件
PChar(' /c '+'"'+LSharingCmd_bat+'"'),//:外部命令的参数
nil,//:LPCTSTR lpDirectory运行的目录参数ShellAPI.pas
SW_HIDE); //:外部命令的返回值无论成功与否------均42
3.2.2、句法:
//ShellExecute组函数:
{$EXTERNALSYM ShellExecute}
function ShellExecute(hWnd: HWND; Operation, FileName, Parameters,
Directory: PChar; ShowCmd: Integer): HINST; stdcall;
{$EXTERNALSYM ShellExecuteA}
function ShellExecuteA(hWnd: HWND; Operation, FileName, Parameters,
Directory: PAnsiChar; ShowCmd: Integer): HINST; stdcall;
{$EXTERNALSYM ShellExecuteW}
function ShellExecuteW(hWnd: HWND; Operation, FileName, Parameters,
Directory: PWideChar; ShowCmd: Integer): HINST; stdcall;
//ShellExecuteEx组函数:
{$EXTERNALSYM ShellExecuteEx}
function ShellExecuteEx(lpExecInfo: PShellExecuteInfo):BOOL; stdcall;
{$EXTERNALSYM ShellExecuteExA}
function ShellExecuteExA(lpExecInfo: PShellExecuteInfoA):BOOL; stdcall;
{$EXTERNALSYM ShellExecuteExW}
function ShellExecuteExW(lpExecInfo: PShellExecuteInfoW):BOOL; stdcall;
ShellExecuteEx组,其中PShellExecuteInfo:
type
PShellExecuteInfoA = ^TShellExecuteInfoA;
PShellExecuteInfoW = ^TShellExecuteInfoW;
PShellExecuteInfo = PShellExecuteInfoA;
{$EXTERNALSYM _SHELLEXECUTEINFOA}
_SHELLEXECUTEINFOA = record
cbSize: DWORD;
fMask: ULONG;
Wnd: HWND;
lpVerb: PAnsiChar;
lpFile: PAnsiChar;
lpParameters: PAnsiChar;
lpDirectory: PAnsiChar;
nShow: Integer;
hInstApp: HINST;
{ Optional fields }
lpIDList: Pointer;
lpClass: PAnsiChar;
hkeyClass: HKEY;
dwHotKey: DWORD;
hIcon: THandle;
hProcess: THandle;
end;
{$EXTERNALSYM _SHELLEXECUTEINFOW}
_SHELLEXECUTEINFOW = record
cbSize: DWORD;
fMask: ULONG;
Wnd: HWND;
lpVerb: PWideChar;
lpFile: PWideChar;
lpParameters: PWideChar;
lpDirectory: PWideChar;
nShow: Integer;
hInstApp: HINST;
{ Optional fields }
lpIDList: Pointer;
lpClass: PWideChar;
hkeyClass: HKEY;
dwHotKey: DWORD;
hIcon: THandle;
hProcess: THandle;
end;
{$EXTERNALSYM _SHELLEXECUTEINFO}
_SHELLEXECUTEINFO = _SHELLEXECUTEINFOA;
TShellExecuteInfoA = _SHELLEXECUTEINFOA;
TShellExecuteInfoW = _SHELLEXECUTEINFOW;
TShellExecuteInfo = TShellExecuteInfoA;
{$EXTERNALSYM SHELLEXECUTEINFOA}
SHELLEXECUTEINFOA = _SHELLEXECUTEINFOA;
{$EXTERNALSYM SHELLEXECUTEINFOW}
SHELLEXECUTEINFOW = _SHELLEXECUTEINFOW;
{$EXTERNALSYM SHELLEXECUTEINFO}
SHELLEXECUTEINFO = SHELLEXECUTEINFOA;
3.2.3、Tray notification definitions托盘通知定义:
type
PNotifyIconDataA = ^TNotifyIconDataA;
PNotifyIconDataW = ^TNotifyIconDataW;
PNotifyIconData = PNotifyIconDataA;
{$EXTERNALSYM _NOTIFYICONDATAA}
_NOTIFYICONDATAA = record
cbSize: DWORD;
Wnd: HWND;
uID: UINT;
uFlags: UINT;
uCallbackMessage: UINT;
hIcon: HICON;
szTip: array [0..63] of AnsiChar;
end;
{$EXTERNALSYM _NOTIFYICONDATAW}
_NOTIFYICONDATAW = record
cbSize: DWORD;
Wnd: HWND;
uID: UINT;
uFlags: UINT;
uCallbackMessage: UINT;
hIcon: HICON;
szTip: array [0..63] of WideChar;
end;
{$EXTERNALSYM _NOTIFYICONDATA}
_NOTIFYICONDATA = _NOTIFYICONDATAA;
TNotifyIconDataA = _NOTIFYICONDATAA;
TNotifyIconDataW = _NOTIFYICONDATAW;
TNotifyIconData = TNotifyIconDataA;
{$EXTERNALSYM NOTIFYICONDATAA}
NOTIFYICONDATAA = _NOTIFYICONDATAA;
{$EXTERNALSYM NOTIFYICONDATAW}
NOTIFYICONDATAW = _NOTIFYICONDATAW;
{$EXTERNALSYM NOTIFYICONDATA}
NOTIFYICONDATA = NOTIFYICONDATAA;
const
{$EXTERNALSYM NIM_ADD}
NIM_ADD = $00000000;
{$EXTERNALSYM NIM_MODIFY}
NIM_MODIFY = $00000001;
{$EXTERNALSYM NIM_DELETE}
NIM_DELETE = $00000002;
{$EXTERNALSYM NIF_MESSAGE}
NIF_MESSAGE = $00000001;
{$EXTERNALSYM NIF_ICON}
NIF_ICON = $00000002;
{$EXTERNALSYM NIF_TIP}
NIF_TIP = $00000004;
{$EXTERNALSYM Shell_NotifyIcon}
function Shell_NotifyIcon(dwMessage: DWORD; lpData: PNotifyIconData): BOOL; stdcall;
{$EXTERNALSYM Shell_NotifyIconA}
function Shell_NotifyIconA(dwMessage: DWORD; lpData: PNotifyIconDataA): BOOL; stdcall;
{$EXTERNALSYM Shell_NotifyIconW}
function Shell_NotifyIconW(dwMessage: DWORD; lpData: PNotifyIconDataW): BOOL; stdcall;